diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 5f17f30b3b0b1..598628936112e 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -28,6 +28,8 @@ Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however *not* meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label. +Discussion comments will get marked as off-topic or deleted. +Repeated discussions on the tracking issue may lead to the tracking issue getting locked. ### Steps $DIR/option-content-move2.rs:11:9 + // | + // LL | let mut var = None; + // | ------- captured outer variable + // LL | func(|| { + // | -- captured by this `FnMut` closure + // LL | // Shouldn't suggest `move ||.as_ref()` here + // LL | move || { + // | ^^^^^^^ `var` is moved here + // LL | + // LL | var = Some(NotCopyable); + // | --- + // | | + // | variable moved due to use in closure + // | move occurs because `var` has type `Option`, which does not implement the `Copy` trait + // | + return; + } + + // Search for an appropriate place for the structured `.clone()` suggestion to be applied. + // If we encounter a statement before the borrow error, we insert a statement there. + for (_, node) in tcx.hir().parent_iter(closure_expr.hir_id) { + if let Node::Stmt(stmt) = node { + let padding = tcx + .sess + .source_map() + .indentation_before(stmt.span) + .unwrap_or_else(|| " ".to_string()); + err.multipart_suggestion_verbose( + "clone the value before moving it into the closure", + vec![ + ( + stmt.span.shrink_to_lo(), + format!("let value = {upvar_name}.clone();\n{padding}"), + ), + (use_span, "value".to_string()), + ], + Applicability::MachineApplicable, + ); + suggested = true; + break; + } else if let Node::Expr(expr) = node + && let ExprKind::Closure(_) = expr.kind + { + // We want to suggest cloning only on the first closure, not + // subsequent ones (like `ui/suggestions/option-content-move2.rs`). + break; + } + } + if !suggested { + // If we couldn't find a statement for us to insert a new `.clone()` statement before, + // we have a bare expression, so we suggest the creation of a new block inline to go + // from `move || val` to `{ let value = val.clone(); move || value }`. + let padding = tcx + .sess + .source_map() + .indentation_before(closure_expr.span) + .unwrap_or_else(|| " ".to_string()); + err.multipart_suggestion_verbose( + "clone the value before moving it into the closure", + vec![ + ( + closure_expr.span.shrink_to_lo(), + format!("{{\n{padding}let value = {upvar_name}.clone();\n{padding}"), + ), + (use_spans.var_or_use(), "value".to_string()), + (closure_expr.span.shrink_to_hi(), format!("\n{padding}}}")), + ], + Applicability::MachineApplicable, + ); + } + } + fn report_cannot_move_from_borrowed_content( &mut self, move_place: Place<'tcx>, @@ -310,10 +429,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { span: Span, use_spans: Option>, ) -> Diag<'tcx> { + let tcx = self.infcx.tcx; // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; + let ty = deref_target_place.ty(self.body, tcx).ty; let upvar_field = self .prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); @@ -363,8 +483,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar = &self.upvars[upvar_field.unwrap().index()]; let upvar_hir_id = upvar.get_root_variable(); - let upvar_name = upvar.to_string(self.infcx.tcx); - let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); + let upvar_name = upvar.to_string(tcx); + let upvar_span = tcx.hir().span(upvar_hir_id); let place_name = self.describe_any_place(move_place.as_ref()); @@ -380,12 +500,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { closure_kind_ty, closure_kind, place_description, ); - self.cannot_move_out_of(span, &place_description) + let closure_span = tcx.def_span(def_id); + let mut err = self + .cannot_move_out_of(span, &place_description) .with_span_label(upvar_span, "captured outer variable") .with_span_label( - self.infcx.tcx.def_span(def_id), + closure_span, format!("captured by this `{closure_kind}` closure"), - ) + ); + self.suggest_clone_of_captured_var_in_move_closure( + &mut err, + upvar_hir_id, + &upvar_name, + use_spans, + ); + err } _ => { let source = self.borrowed_content_source(deref_base); @@ -415,7 +544,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), (_, _, _) => self.cannot_move_out_of( span, - &source.describe_for_unnamed_place(self.infcx.tcx), + &source.describe_for_unnamed_place(tcx), ), } } @@ -447,7 +576,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(expr) = self.find_expr(span) { - self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span)); + self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None); } err.subdiagnostic( @@ -482,7 +611,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(expr) = self.find_expr(use_span) { - self.suggest_cloning(err, place_ty, expr, self.find_expr(span)); + self.suggest_cloning( + err, + place_ty, + expr, + self.find_expr(span), + Some(use_spans), + ); } err.subdiagnostic( @@ -595,7 +730,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); if let Some(expr) = self.find_expr(binding_span) { - self.suggest_cloning(err, bind_to.ty, expr, None); + self.suggest_cloning(err, bind_to.ty, expr, None, None); } err.subdiagnostic( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8b31421719089..5d74a01aa2076 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -7,6 +7,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; use rustc_infer::traits; +use rustc_middle::bug; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt}; use rustc_middle::{ diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 2fe75fe2a2bff..d8d582b0ad1c3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -18,6 +18,7 @@ use rustc_infer::infer::{ error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, RelateParamBound, }; +use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::GenericArgs; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index cda6136040412..28c5c505f7916 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -11,6 +11,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a69b644c4dcc0..47c83e0bb2bb6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -4,7 +4,6 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![feature(assert_matches)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_chains)] @@ -14,8 +13,6 @@ #![feature(stmt_expr_attributes)] #![feature(try_blocks)] -#[macro_use] -extern crate rustc_middle; #[macro_use] extern crate tracing; @@ -33,6 +30,7 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; use rustc_target::abi::FieldIdx; @@ -1056,18 +1054,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared | BorrowKind::Fake) - | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { - Control::Continue - } + (Read(_), BorrowKind::Shared | BorrowKind::Fake(_)) + | ( + Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))), + BorrowKind::Mut { .. }, + ) => Control::Continue, - (Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => { + (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be // disallowed on NLL). See rust-lang/rust#56254 Control::Continue } - (Write(WriteKind::Move), BorrowKind::Fake) => { + (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => { // Handled by initialization checks. Control::Continue } @@ -1175,10 +1174,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { let access_kind = match bk { - BorrowKind::Fake => { + BorrowKind::Fake(FakeBorrowKind::Shallow) => { (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => { + (Deep, Read(ReadKind::Borrow(bk))) + } BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { @@ -1197,7 +1198,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { flow_state, ); - let action = if bk == BorrowKind::Fake { + let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) { InitializationRequiringAction::MatchOn } else { InitializationRequiringAction::Borrow @@ -1557,7 +1558,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake => false, + BorrowKind::Shared | BorrowKind::Fake(_) => false, BorrowKind::Mut { .. } => true, }); @@ -2122,14 +2123,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Fake), + | WriteKind::MutableBorrow(BorrowKind::Fake(_)), ) | Write( WriteKind::Move | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Fake), + | WriteKind::MutableBorrow(BorrowKind::Fake(_)), ) => { if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() && !self.has_buffered_diags() @@ -2153,7 +2154,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_)) | ReadKind::Copy, ) => { // Access authorized diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 7e8dba43b715e..ad3c3e6d07932 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -54,8 +54,9 @@ use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; use rustc_hir as hir; +use rustc_middle::bug; use rustc_middle::mir::{ - Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, + Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, }; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; @@ -271,10 +272,10 @@ fn place_components_conflict<'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Fake + if borrow_kind == BorrowKind::Fake(FakeBorrowKind::Shallow) && borrow_place.projection.len() < access_place.projection.len() { - debug!("borrow_conflicts_with_place: fake borrow"); + debug!("borrow_conflicts_with_place: shallow borrow"); false } else { debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 956de1dec9b2b..a1e59977ede5a 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -1,6 +1,9 @@ use rustc_data_structures::graph::dominators::Dominators; +use rustc_middle::bug; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; +use rustc_middle::mir::{ + self, BasicBlock, Body, FakeBorrowKind, Location, NonDivergingIntrinsic, Place, Rvalue, +}; use rustc_middle::mir::{BorrowKind, Mutability, Operand}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; @@ -239,10 +242,12 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { let access_kind = match bk { - BorrowKind::Fake => { + BorrowKind::Fake(FakeBorrowKind::Shallow) => { (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => { + (Deep, Read(ReadKind::Borrow(bk))) + } BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { @@ -357,8 +362,11 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { // have already taken the reservation } - (Read(_), BorrowKind::Fake | BorrowKind::Shared) - | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Fake(_) | BorrowKind::Shared) + | ( + Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))), + BorrowKind::Mut { .. }, + ) => { // Reads don't invalidate shared or shallow borrows } @@ -403,7 +411,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake => false, + BorrowKind::Shared | BorrowKind::Fake(_) => false, BorrowKind::Mut { .. } => true, }); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index dd75548a15df7..78465ad7975d9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -11,6 +11,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::outlives::test_type_match; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; +use rustc_middle::bug; use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index a950f10787b36..49d3f7381d910 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -2,6 +2,7 @@ use std::fmt; use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::canonical::Canonical; +use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::def_id::DefId; diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index de75a9857f8b5..5aa8fe213814d 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -4,6 +4,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; +use rustc_middle::bug; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 51ae7d14e4386..38ec9f7678ebc 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -2,6 +2,7 @@ use itertools::{Either, Itertools}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::visit::{TyContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, SourceInfo}; +use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 61fa84666744b..b67c5d8581839 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -33,6 +33,7 @@ use rustc_middle::ty::{ OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_middle::ty::{GenericArgsRef, UserArgs}; +use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index d67ede57e7874..5e4b3e532c413 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -5,6 +5,7 @@ use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; +use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::FnMutDelegate; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9c65f64b03fec..070238fc37882 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -27,6 +27,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym}; use rustc_span::Symbol; use std::iter; diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 2a5bc58af3b3d..0f15899031938 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -118,6 +118,8 @@ builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Un builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments +builtin_macros_expected_comma_in_list = expected token: `,` + builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern builtin_macros_expected_register_class_or_explicit_register = expected register class or explicit register @@ -219,12 +221,16 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants .help = consider a manual implementation of `Default` +builtin_macros_only_one_argument = {$name} takes 1 argument + builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]` builtin_macros_requires_cfg_pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required +builtin_macros_takes_no_arguments = {$name} takes no arguments + builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests .label = `{$kind}` because of this diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index bc94e0b972b47..064cf7d7f0f8e 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand( +pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 137ac44157924..49b1b8cf99268 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,3 +1,5 @@ +use crate::errors; +use crate::util::expr_to_spanned_string; use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -16,8 +18,6 @@ use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; -use crate::errors; - pub struct AsmArgs { pub templates: Vec>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index d200179f3a0ae..c75050f270188 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -15,7 +15,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use thin_vec::thin_vec; -pub fn expand_assert<'cx>( +pub(crate) fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, span: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5dc9bbacd0629..827719d794493 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -11,7 +11,7 @@ use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::Span; -pub fn expand_cfg( +pub(crate) fn expand_cfg( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 93f7d09546b70..5f63a8ae0a8c2 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -18,6 +18,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; +use tracing::instrument; pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, @@ -246,18 +247,18 @@ impl MutVisitor for CfgEval<'_, '_> { } fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) + mut_visit::noop_flat_map_item(configure!(self, item), self) } fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) + mut_visit::noop_flat_map_item(configure!(self, item), self) } fn flat_map_foreign_item( &mut self, foreign_item: P, ) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self) + mut_visit::noop_flat_map_item(configure!(self, foreign_item), self) } fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 2f2a87fc9aa00..a08e8b2819b56 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -1,11 +1,11 @@ // The compiler code necessary to support the compile_error! extension. +use crate::util::get_single_str_from_tts; use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::get_single_str_from_tts; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::Span; -pub fn expand_compile_error<'cx>( +pub(crate) fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 93a7ac05a9bef..15af79ef67d4a 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,13 +1,12 @@ +use crate::errors; +use crate::util::get_exprs_from_tts; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ExprKind, LitKind, UnOp}; -use rustc_expand::base::get_exprs_from_tts; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; -use crate::errors; - -pub fn expand_concat( +pub(crate) fn expand_concat( cx: &mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 45fec2945788b..3130870df4105 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,11 +1,10 @@ +use crate::errors; +use crate::util::get_exprs_from_tts; use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; -use rustc_expand::base::get_exprs_from_tts; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; -use crate::errors; - /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( cx: &ExtCtxt<'_>, @@ -108,7 +107,7 @@ fn handle_array_element( None } -pub fn expand_concat_bytes( +pub(crate) fn expand_concat_bytes( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 3ddb0ae45b51a..13729a9d250fe 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use crate::errors; -pub fn expand_concat_idents<'cx>( +pub(crate) fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 4f412cf79d91f..d14858e5c1db3 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -3,14 +3,18 @@ use crate::errors; use rustc_ast as ast; use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; -use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; +use rustc_expand::base::{ + Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, +}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::{ErrorGuaranteed, Span}; -pub(crate) struct Expander(pub bool); +pub(crate) struct Expander { + pub is_const: bool, +} impl MultiItemModifier for Expander { fn expand( @@ -58,7 +62,12 @@ impl MultiItemModifier for Expander { report_path_args(sess, meta); meta.path.clone() }) - .map(|path| (path, dummy_annotatable(), None, self.0)) + .map(|path| DeriveResolution { + path, + item: dummy_annotatable(), + exts: None, + is_const: self.is_const, + }) .collect() } _ => vec![], @@ -67,15 +76,15 @@ impl MultiItemModifier for Expander { // Do not configure or clone items unless necessary. match &mut resolutions[..] { [] => {} - [(_, first_item, ..), others @ ..] => { - *first_item = cfg_eval( + [first, others @ ..] => { + first.item = cfg_eval( sess, features, item.clone(), ecx.current_expansion.lint_node_id, ); - for (_, item, _, _) in others { - *item = first_item.clone(); + for other in others { + other.item = first.item.clone(); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 26ef3da3a915c..97e2344ff30e5 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -5,7 +5,7 @@ use rustc_ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::Span; -pub fn expand_deriving_copy( +pub(crate) fn expand_deriving_copy( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, @@ -28,7 +28,7 @@ pub fn expand_deriving_copy( trait_def.expand(cx, mitem, item, push); } -pub fn expand_deriving_const_param_ty( +pub(crate) fn expand_deriving_const_param_ty( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index cb1c9ef90bde7..abcb402a46f8e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_clone( +pub(crate) fn expand_deriving_clone( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 45c4467a1097c..53a1513160542 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_eq( +pub(crate) fn expand_deriving_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1d7a69540ab89..8470d466a233c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_ord( +pub(crate) fn expand_deriving_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, @@ -39,7 +39,7 @@ pub fn expand_deriving_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 234918ae42961..dc73caa4ad5be 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_partial_eq( +pub(crate) fn expand_deriving_partial_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 63311c897aba9..006e5a3d268a6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_partial_ord( +pub(crate) fn expand_deriving_partial_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 8b681db967050..57ec0435e3e05 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_debug( +pub(crate) fn expand_deriving_debug( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 34798ab0a17b0..e9851c87aeaef 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -10,7 +10,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_rustc_decodable( +pub(crate) fn expand_deriving_rustc_decodable( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 328770ce10d2c..bf92ddb33701c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -12,7 +12,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_default( +pub(crate) fn expand_deriving_default( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2e5f1173825a1..3bd74d8d0198a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -94,7 +94,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand_deriving_rustc_encodable( +pub(crate) fn expand_deriving_rustc_encodable( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 85d54e9257d8c..52c1ba1757b1e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -174,8 +174,8 @@ //! ) //! ``` -pub use StaticFields::*; -pub use SubstructureFields::*; +pub(crate) use StaticFields::*; +pub(crate) use SubstructureFields::*; use crate::{deriving, errors}; use rustc_ast::ptr::P; @@ -195,9 +195,9 @@ use std::vec; use thin_vec::{thin_vec, ThinVec}; use ty::{Bounds, Path, Ref, Self_, Ty}; -pub mod ty; +pub(crate) mod ty; -pub struct TraitDef<'a> { +pub(crate) struct TraitDef<'a> { /// The span for the current #[derive(Foo)] header. pub span: Span, @@ -224,7 +224,7 @@ pub struct TraitDef<'a> { pub is_const: bool, } -pub struct MethodDef<'a> { +pub(crate) struct MethodDef<'a> { /// name of the method pub name: Symbol, /// List of generics, e.g., `R: rand::Rng` @@ -248,7 +248,7 @@ pub struct MethodDef<'a> { /// How to handle fieldless enum variants. #[derive(PartialEq)] -pub enum FieldlessVariantsStrategy { +pub(crate) enum FieldlessVariantsStrategy { /// Combine fieldless variants into a single match arm. /// This assumes that relevant information has been handled /// by looking at the enum's discriminant. @@ -263,7 +263,7 @@ pub enum FieldlessVariantsStrategy { } /// All the data about the data structure/method being derived upon. -pub struct Substructure<'a> { +pub(crate) struct Substructure<'a> { /// ident of self pub type_ident: Ident, /// Verbatim access to any non-selflike arguments, i.e. arguments that @@ -273,7 +273,7 @@ pub struct Substructure<'a> { } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { +pub(crate) struct FieldInfo { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. @@ -287,13 +287,13 @@ pub struct FieldInfo { } #[derive(Copy, Clone)] -pub enum IsTuple { +pub(crate) enum IsTuple { No, Yes, } /// Fields for a static method -pub enum StaticFields { +pub(crate) enum StaticFields { /// Tuple and unit structs/enum variants like this. Unnamed(Vec, IsTuple), /// Normal structs/struct variants. @@ -301,7 +301,7 @@ pub enum StaticFields { } /// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { +pub(crate) enum SubstructureFields<'a> { /// A non-static method where `Self` is a struct. Struct(&'a ast::VariantData, Vec), @@ -329,10 +329,10 @@ pub enum SubstructureFields<'a> { /// Combine the values of all the fields together. The last argument is /// all the fields of all the structures. -pub type CombineSubstructureFunc<'a> = +pub(crate) type CombineSubstructureFunc<'a> = Box, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; -pub fn combine_substructure( +pub(crate) fn combine_substructure( f: CombineSubstructureFunc<'_>, ) -> RefCell> { RefCell::new(f) @@ -349,7 +349,7 @@ struct TypeParameter { /// avoiding the insertion of any unnecessary blocks. /// /// The statements come before the expression. -pub struct BlockOrExpr(ThinVec, Option>); +pub(crate) struct BlockOrExpr(ThinVec, Option>); impl BlockOrExpr { pub fn new_stmts(stmts: ThinVec) -> BlockOrExpr { @@ -1647,7 +1647,7 @@ impl<'a> TraitDef<'a> { /// The function passed to `cs_fold` is called repeatedly with a value of this /// type. It describes one part of the code generation. The result is always an /// expression. -pub enum CsFold<'a> { +pub(crate) enum CsFold<'a> { /// The basic case: a field expression for one or more selflike args. E.g. /// for `PartialEq::eq` this is something like `self.x == other.x`. Single(&'a FieldInfo), @@ -1662,7 +1662,7 @@ pub enum CsFold<'a> { /// Folds over fields, combining the expressions for each field in a sequence. /// Statics may not be folded over. -pub fn cs_fold( +pub(crate) fn cs_fold( use_foldl: bool, cx: &ExtCtxt<'_>, trait_span: Span, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 1888332468326..f01d586033e09 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -1,7 +1,7 @@ //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use //! when specifying impls to be derived. -pub use Ty::*; +pub(crate) use Ty::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; @@ -14,14 +14,14 @@ use thin_vec::ThinVec; /// A path, e.g., `::std::option::Option::` (global). Has support /// for type parameters. #[derive(Clone)] -pub struct Path { +pub(crate) struct Path { path: Vec, params: Vec>, kind: PathKind, } #[derive(Clone)] -pub enum PathKind { +pub(crate) enum PathKind { Local, Global, Std, @@ -72,7 +72,7 @@ impl Path { /// A type. Supports pointers, Self, and literals. #[derive(Clone)] -pub enum Ty { +pub(crate) enum Ty { Self_, /// A reference. Ref(Box, ast::Mutability), @@ -83,7 +83,7 @@ pub enum Ty { Unit, } -pub fn self_ref() -> Ty { +pub(crate) fn self_ref() -> Ty { Ref(Box::new(Self_), ast::Mutability::Not) } @@ -163,7 +163,7 @@ fn mk_ty_param( /// Bounds on type parameters. #[derive(Clone)] -pub struct Bounds { +pub(crate) struct Bounds { pub bounds: Vec<(Symbol, Vec)>, } @@ -196,7 +196,7 @@ impl Bounds { } } -pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P, ast::ExplicitSelf) { +pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P, ast::ExplicitSelf) { // This constructs a fresh `self` path. let self_path = cx.expr_self(span); let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 41e27f6558668..dcd9281986511 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use thin_vec::thin_vec; -pub fn expand_deriving_hash( +pub(crate) fn expand_deriving_hash( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 9f786d22c932f..d6e2d1d4d07f6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -20,24 +20,24 @@ macro path_std($($x:tt)*) { generic::ty::Path::new( pathvec_std!( $($x)* ) ) } -pub mod bounds; -pub mod clone; -pub mod debug; -pub mod decodable; -pub mod default; -pub mod encodable; -pub mod hash; +pub(crate) mod bounds; +pub(crate) mod clone; +pub(crate) mod debug; +pub(crate) mod decodable; +pub(crate) mod default; +pub(crate) mod encodable; +pub(crate) mod hash; #[path = "cmp/eq.rs"] -pub mod eq; +pub(crate) mod eq; #[path = "cmp/ord.rs"] -pub mod ord; +pub(crate) mod ord; #[path = "cmp/partial_eq.rs"] -pub mod partial_eq; +pub(crate) mod partial_eq; #[path = "cmp/partial_ord.rs"] -pub mod partial_ord; +pub(crate) mod partial_ord; -pub mod generic; +pub(crate) mod generic; pub(crate) type BuiltinDeriveFn = fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index bb3c83e8c0e3f..cc385bade4703 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -16,7 +16,7 @@ use rustc_span::Span; /// /// `$crate` will refer to either the `std` or `core` crate depending on which /// one we're expanding from. -pub fn expand_panic<'cx>( +pub(crate) fn expand_panic<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -29,7 +29,7 @@ pub fn expand_panic<'cx>( /// - `$crate::panic::unreachable_2015!(...)` or /// - `$crate::panic::unreachable_2021!(...)` /// depending on the edition. -pub fn expand_unreachable<'cx>( +pub(crate) fn expand_unreachable<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -69,7 +69,7 @@ fn expand<'cx>( )) } -pub fn use_panic_2021(mut span: Span) -> bool { +pub(crate) fn use_panic_2021(mut span: Span) -> bool { // To determine the edition, we check the first span up the expansion // stack that does not have #[allow_internal_unstable(edition_panic)]. // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 9387304594378..b03e14cf2630d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -3,10 +3,11 @@ // interface. // +use crate::errors; +use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts}; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; -use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -14,8 +15,6 @@ use std::env; use std::env::VarError; use thin_vec::thin_vec; -use crate::errors; - fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result { let var = var.as_str(); if let Some(value) = cx.sess.opts.logical_env.get(var) { @@ -26,7 +25,7 @@ fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result( +pub(crate) fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -66,7 +65,7 @@ pub fn expand_option_env<'cx>( ExpandResult::Ready(MacEager::expr(e)) } -pub fn expand_env<'cx>( +pub(crate) fn expand_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 6b6647ef085c2..d157703723beb 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -579,7 +579,7 @@ pub(crate) struct FormatUnknownTrait<'a> { style = "tool-only", applicability = "maybe-incorrect" )] -pub struct FormatUnknownTraitSugg { +pub(crate) struct FormatUnknownTraitSugg { #[primary_span] pub span: Span, pub fmt: &'static str, @@ -601,7 +601,7 @@ impl Subdiagnostic for FormatUnusedArg { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.arg("named", self.named); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); @@ -842,3 +842,26 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister { #[primary_span] pub(crate) span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_expected_comma_in_list)] +pub(crate) struct ExpectedCommaInList { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_only_one_argument)] +pub(crate) struct OnlyOneArgument<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_takes_no_arguments)] +pub(crate) struct TakesNoArguments<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 51d6058a744fc..2c717661a1c43 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,3 +1,5 @@ +use crate::errors; +use crate::util::expr_to_spanned_string; use parse::Position::ArgumentNamed; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; @@ -10,14 +12,13 @@ use rustc_ast::{ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::*; +use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; +use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; use rustc_parse::parser::Recovered; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; -use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; - // The format_args!() macro is expanded in three steps: // 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, // but doesn't parse the template (the literal) itself. @@ -38,8 +39,6 @@ enum PositionUsedAs { } use PositionUsedAs::*; -use crate::errors; - #[derive(Debug)] struct MacroInput { fmtstr: P, @@ -1001,7 +1000,7 @@ fn expand_format_args_impl<'cx>( }) } -pub fn expand_format_args<'cx>( +pub(crate) fn expand_format_args<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -1009,7 +1008,7 @@ pub fn expand_format_args<'cx>( expand_format_args_impl(ecx, sp, tts, false) } -pub fn expand_format_args_nl<'cx>( +pub(crate) fn expand_format_args_nl<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 099defd511b5b..a1630ad1379e4 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -12,7 +12,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; -pub fn expand( +pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 1b4c6041294f4..744c7f9d09006 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -19,11 +19,7 @@ extern crate proc_macro; -#[macro_use] -extern crate tracing; - use crate::deriving::*; - use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; @@ -50,13 +46,13 @@ mod pattern_type; mod source_util; mod test; mod trace_macros; -mod util; pub mod asm; pub mod cmdline_attrs; pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; +pub mod util; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -109,8 +105,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, - derive: derive::Expander(false), - derive_const: derive::Expander(true), + derive: derive::Expander { is_const: false }, + derive_const: derive::Expander { is_const: true }, global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, diff --git a/compiler/rustc_builtin_macros/src/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs index 288a475ac241c..205f21ae7c9d3 100644 --- a/compiler/rustc_builtin_macros/src/log_syntax.rs +++ b/compiler/rustc_builtin_macros/src/log_syntax.rs @@ -2,7 +2,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -pub fn expand_log_syntax<'cx>( +pub(crate) fn expand_log_syntax<'cx>( _cx: &'cx mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 54039c2c5386b..31f5656df135e 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -3,7 +3,7 @@ use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::{sym, Span}; -pub fn expand<'cx>( +pub(crate) fn expand<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index c79ae716806cd..47b2ee975ca89 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,3 +1,6 @@ +use crate::util::{ + check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, +}; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token; @@ -5,11 +8,8 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_expand::base::{ - check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, - resolve_path, + resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, }; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt}; -use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult}; use rustc_expand::module::DirOwnership; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; @@ -26,7 +26,7 @@ use std::rc::Rc; // a given file into the current one. /// line!(): expands to the current line number -pub fn expand_line( +pub(crate) fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -41,7 +41,7 @@ pub fn expand_line( } /* column!(): expands to the current column number */ -pub fn expand_column( +pub(crate) fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -58,7 +58,7 @@ pub fn expand_column( /// file!(): expands to the current filename */ /// The source_file (`loc.file`) contains a bunch more information we could spit /// out if we wanted. -pub fn expand_file( +pub(crate) fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -78,7 +78,7 @@ pub fn expand_file( ))) } -pub fn expand_stringify( +pub(crate) fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -88,7 +88,7 @@ pub fn expand_stringify( ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))) } -pub fn expand_mod( +pub(crate) fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -104,7 +104,7 @@ pub fn expand_mod( /// include! : parse the given file as an expr /// This is generally a bad idea because it's going to behave /// unhygienically. -pub fn expand_include<'cx>( +pub(crate) fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -181,7 +181,7 @@ pub fn expand_include<'cx>( } /// `include_str!`: read the given file, insert it as a literal string expr -pub fn expand_include_str( +pub(crate) fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -210,7 +210,7 @@ pub fn expand_include_str( }) } -pub fn expand_include_bytes( +pub(crate) fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index c7568f1461c10..1e4bf4611cfb2 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -12,6 +12,7 @@ use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; use std::assert_matches::assert_matches; use std::iter; use thin_vec::{thin_vec, ThinVec}; +use tracing::debug; /// #[test_case] is used by custom test authors to mark tests /// When building for test, it needs to make the item public and gensym the name @@ -20,7 +21,7 @@ use thin_vec::{thin_vec, ThinVec}; /// /// We mark item with an inert attribute "rustc_test_marker" which the test generation /// logic will pick up on. -pub fn expand_test_case( +pub(crate) fn expand_test_case( ecx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -73,7 +74,7 @@ pub fn expand_test_case( vec![ret] } -pub fn expand_test( +pub(crate) fn expand_test( cx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -84,7 +85,7 @@ pub fn expand_test( expand_test_or_bench(cx, attr_sp, item, false) } -pub fn expand_bench( +pub(crate) fn expand_bench( cx: &mut ExtCtxt<'_>, attr_sp: Span, meta_item: &ast::MetaItem, @@ -95,7 +96,7 @@ pub fn expand_bench( expand_test_or_bench(cx, attr_sp, item, true) } -pub fn expand_test_or_bench( +pub(crate) fn expand_test_or_bench( cx: &ExtCtxt<'_>, attr_sp: Span, item: Annotatable, diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index 696d99004ba01..4833ec32f76e1 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -4,7 +4,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult use rustc_span::symbol::kw; use rustc_span::Span; -pub fn expand_trace_macros( +pub(crate) fn expand_trace_macros( cx: &mut ExtCtxt<'_>, sp: Span, tt: TokenStream, diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index ad6b09ba57458..8dc7bc14ec3e6 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,11 +1,16 @@ -use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use crate::errors; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; +use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; +use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; -use rustc_parse::validate_attr; -use rustc_span::Symbol; +use rustc_parse::{parser, validate_attr}; +use rustc_session::errors::report_lit_error; +use rustc_span::{BytePos, Span, Symbol}; -pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { +pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { // All the built-in macro attributes are "words" at the moment. let template = AttributeTemplate { word: true, ..Default::default() }; validate_attr::check_builtin_meta_item( @@ -19,7 +24,7 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na /// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when /// an attribute may have been mistakenly duplicated. -pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { +pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { let attrs: Option<&[Attribute]> = match item { Annotatable::Item(item) => Some(&item.attrs), Annotatable::TraitItem(item) => Some(&item.attrs), @@ -46,3 +51,178 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: } } } + +/// `Ok` represents successfully retrieving the string literal at the correct +/// position, e.g., `println("abc")`. +type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>; + +/// - `Ok` is returned when the conversion to a string literal is unsuccessful, +/// but another type of expression is obtained instead. +/// - `Err` is returned when the conversion process fails. +type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>; + +/// Extracts a string literal from the macro expanded version of `expr`, +/// returning a diagnostic error of `err_msg` if `expr` is not a string literal. +/// The returned bool indicates whether an applicable suggestion has already been +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))` +/// indicates that an ast error was encountered. +// FIXME(Nilstrieb) Make this function setup translatable +#[allow(rustc::untranslatable_diagnostic)] +pub(crate) fn expr_to_spanned_string<'a>( + cx: &'a mut ExtCtxt<'_>, + expr: P, + err_msg: &'static str, +) -> ExpandResult, ()> { + if !cx.force_mode + && let ast::ExprKind::MacCall(m) = &expr.kind + && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() + { + return ExpandResult::Retry(()); + } + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + + ExpandResult::Ready(Err(match expr.kind { + ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Str(s, style)) => { + return ExpandResult::Ready(Ok((s, style, expr.span))); + } + Ok(ast::LitKind::ByteStr(..)) => { + let mut err = cx.dcx().struct_span_err(expr.span, err_msg); + let span = expr.span.shrink_to_lo(); + err.span_suggestion( + span.with_hi(span.lo() + BytePos(1)), + "consider removing the leading `b`", + "", + Applicability::MaybeIncorrect, + ); + Ok((err, true)) + } + Ok(ast::LitKind::Err(guar)) => Err(guar), + Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), + }, + ast::ExprKind::Err(guar) => Err(guar), + ast::ExprKind::Dummy => { + cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") + } + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), + })) +} + +/// Extracts a string literal from the macro expanded version of `expr`, +/// emitting `err_msg` if `expr` is not a string literal. This does not stop +/// compilation on error, merely emits a non-fatal error and returns `Err`. +pub(crate) fn expr_to_string( + cx: &mut ExtCtxt<'_>, + expr: P, + err_msg: &'static str, +) -> ExpandResult, ()> { + expr_to_spanned_string(cx, expr, err_msg).map(|res| { + res.map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, style, _)| (symbol, style)) + }) +} + +/// Non-fatally assert that `tts` is empty. Note that this function +/// returns even when `tts` is non-empty, macros that *need* to stop +/// compilation should call `cx.diagnostic().abort_if_errors()` +/// (this should be done as rarely as possible). +pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { + if !tts.is_empty() { + cx.dcx().emit_err(errors::TakesNoArguments { span, name }); + } +} + +/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. +pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> { + let guar = match p.parse_expr() { + Ok(expr) => return Ok(expr), + Err(err) => err.emit(), + }; + while p.token != token::Eof { + p.bump(); + } + Err(guar) +} + +/// Interpreting `tts` as a comma-separated sequence of expressions, +/// expect exactly one string literal, or emit an error and return `Err`. +pub(crate) fn get_single_str_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> ExpandResult, ()> { + get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s)) +} + +pub(crate) fn get_single_str_spanned_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> ExpandResult, ()> { + let mut p = cx.new_parser_from_tts(tts); + if p.token == token::Eof { + let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + return ExpandResult::Ready(Err(guar)); + } + let ret = match parse_expr(&mut p) { + Ok(ret) => ret, + Err(guar) => return ExpandResult::Ready(Err(guar)), + }; + let _ = p.eat(&token::Comma); + + if p.token != token::Eof { + cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + } + expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| { + res.map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, _style, span)| (symbol, span)) + }) +} + +/// Extracts comma-separated expressions from `tts`. +/// On error, emit it, and return `Err`. +pub(crate) fn get_exprs_from_tts( + cx: &mut ExtCtxt<'_>, + tts: TokenStream, +) -> ExpandResult>, ErrorGuaranteed>, ()> { + let mut p = cx.new_parser_from_tts(tts); + let mut es = Vec::new(); + while p.token != token::Eof { + let expr = match parse_expr(&mut p) { + Ok(expr) => expr, + Err(guar) => return ExpandResult::Ready(Err(guar)), + }; + if !cx.force_mode + && let ast::ExprKind::MacCall(m) = &expr.kind + && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() + { + return ExpandResult::Retry(()); + } + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + + es.push(expr); + if p.eat(&token::Comma) { + continue; + } + if p.token != token::Eof { + let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span }); + return ExpandResult::Ready(Err(guar)); + } + } + ExpandResult::Ready(Ok(es)) +} diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 8fdc1941de88f..33fe52ddbdd64 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -16,9 +16,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arbitrary" @@ -34,9 +34,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cfg-if" @@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a535eb1cf5a6003197dc569320c40c1cb2d2f97ef5d5348eebf067f20957381" +checksum = "79b27922a6879b5b5361d0a084cb0b1941bf109a98540addcb932da13b68bed4" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b5066db32cec1492573827183af2142d2d88fe85a83cfc9e73f0f63d3788d4" +checksum = "304c455b28bf56372729acb356afbb55d622f2b0f2f7837aa5e57c138acaac4d" dependencies = [ "bumpalo", "cranelift-bforest", @@ -67,7 +67,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "log", "regalloc2", "smallvec", @@ -76,39 +76,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64942e5774308e835fbad4dd25f253105412c90324631910e1ec27963147bddb" +checksum = "1653c56b99591d07f67c5ca7f9f25888948af3f4b97186bff838d687d666f613" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39c33db9a86dd6d8d04166a10c53deb477aeea3500eaaefca682e4eda9bb986" +checksum = "f5b6a9cf6b6eb820ee3f973a0db313c05dc12d370f37b4fe9630286e1672573f" [[package]] name = "cranelift-control" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7fc4937613aea3156a0538800a17bf56f345a5da2e79ae3df58488c93d867f" +checksum = "d9d06e6bf30075fb6bed9e034ec046475093392eea1aff90eb5c44c4a033d19a" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85575e79a153ce1ddbfb7fe1813519b4bfe1eb200cc9c8353b45ad123ae4d36" +checksum = "29be04f931b73cdb9694874a295027471817f26f26d2f0ebe5454153176b6e3a" [[package]] name = "cranelift-frontend" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc31d6c0ab2249fe0c21e988256b42f5f401ab2673b4fc40076c82a698bdfb9" +checksum = "a07fd7393041d7faa2f37426f5dc7fc04003b70988810e8c063beefeff1cd8f9" dependencies = [ "cranelift-codegen", "log", @@ -118,15 +118,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc14f37e3314c0e4c53779c2f46753bf242efff76ee9473757a1fff3b495ad37" +checksum = "f341d7938caa6dff8149dac05bb2b53fc680323826b83b4cf175ab9f5139a3c9" [[package]] name = "cranelift-jit" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdd1942f3233176a68c285380dbc84ff0440246a1bce308611c0a385b56ab18" +checksum = "42733555e06433f1461570e09dbd756dafc228b4dac75c597cdbdc518de07522" dependencies = [ "anyhow", "cranelift-codegen", @@ -139,14 +139,14 @@ dependencies = [ "region", "target-lexicon", "wasmtime-jit-icache-coherence", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "cranelift-module" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121b2b5a16912554a1b9aace75b9b21eca49f28e33cbfbad4786dd9bc5361a5c" +checksum = "84950af02bb85f3da764d53a953b43bb29a732e793d4fe24637a61591be9a024" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ea5375f76ab31f9800a23fb2b440810286a6f669a3eb467cdd7ff255ea64268" +checksum = "82af6066e6448d26eeabb7aa26a43f7ff79f8217b06bade4ee6ef230aecc8880" dependencies = [ "cranelift-codegen", "libc", @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.106.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34e04419ab41661e973d90a73aa7b12771455394dae7a69b101a9b7e7589db7" +checksum = "00af56107039ed150391df6f753298c7b08f2b6a2e0727d216b5fa599d684d8b" dependencies = [ "anyhow", "cranelift-codegen", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -222,21 +222,21 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", ] [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] @@ -247,19 +247,19 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets", ] [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "mach" @@ -272,42 +272,42 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "object" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d" dependencies = [ "crc32fast", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -369,9 +369,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.11.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" @@ -381,9 +381,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.47" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -410,13 +410,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "19.0.0" +version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796e4b4989db62899d2117e1e0258b839d088c044591b14e3a0396e7b3ae53a" +checksum = "7a9f93a3289057b26dc75eb84d6e60d7694f7d169c7c09597495de6e016a13ff" dependencies = [ "cfg-if", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -441,137 +441,78 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "zerocopy" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index d8a855b038307..2015cdbcc2a74 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.106.0", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.106.0" } -cranelift-module = { version = "0.106.0" } -cranelift-native = { version = "0.106.0" } -cranelift-jit = { version = "0.106.0", optional = true } -cranelift-object = { version = "0.106.0" } +cranelift-codegen = { version = "0.107.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.107.0" } +cranelift-module = { version = "0.107.0" } +cranelift-native = { version = "0.107.0" } +cranelift-jit = { version = "0.107.0", optional = true } +cranelift-object = { version = "0.107.0" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} -object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.33", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.8.0", optional = true } diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs index 2e7ba1b2060b6..ecf303c30b6c3 100644 --- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -43,7 +43,13 @@ pub(crate) fn run( let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); cmd.arg("--"); cmd.arg("--pairs"); - cmd.args(pairs); + cmd.args( + if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) { + &pairs[..] + } else { + &pairs[..2] + }, + ); cmd.arg("--add-rustc-codegen-backend"); match cg_clif_dylib { CodegenBackend::Local(path) => { diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 9efb6ed715ca7..76104901474c2 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -290,7 +290,7 @@ pub(crate) fn run_tests( && !skip_tests.contains(&"testsuite.extended_sysroot"); if run_base_sysroot || run_extended_sysroot { - let mut target_compiler = build_sysroot::build_sysroot( + let target_compiler = build_sysroot::build_sysroot( dirs, channel, sysroot_kind, @@ -299,11 +299,8 @@ pub(crate) fn run_tests( rustup_toolchain_name, target_triple.clone(), ); - // Rust's build system denies a couple of lints that trigger on several of the test - // projects. Changing the code to fix them is not worth it, so just silence all lints. - target_compiler.rustflags.push("--cap-lints=allow".to_owned()); - let runner = TestRunner::new( + let mut runner = TestRunner::new( dirs.clone(), target_compiler, use_unstable_features, @@ -319,6 +316,9 @@ pub(crate) fn run_tests( } if run_extended_sysroot { + // Rust's build system denies a couple of lints that trigger on several of the test + // projects. Changing the code to fix them is not worth it, so just silence all lints. + runner.target_compiler.rustflags.push("--cap-lints=allow".to_owned()); runner.run_testsuite(EXTENDED_SYSROOT_SUITE); } else { eprintln!("[SKIP] extended_sysroot tests"); diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index 117eed5afd8ab..da70ca7943983 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,4 +1,5 @@ #![feature(start, core_intrinsics, alloc_error_handler, lang_items)] +#![allow(internal_features)] #![no_std] extern crate alloc; diff --git a/compiler/rustc_codegen_cranelift/example/alloc_system.rs b/compiler/rustc_codegen_cranelift/example/alloc_system.rs index e64daf96b01c9..441f3cd298743 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_system.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_system.rs @@ -80,7 +80,6 @@ mod platform { extern "system" { fn GetProcessHeap() -> HANDLE; fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; - fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; fn GetLastError() -> DWORD; } @@ -111,7 +110,7 @@ mod platform { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { let header = get_header(ptr); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); diff --git a/compiler/rustc_codegen_cranelift/example/example.rs b/compiler/rustc_codegen_cranelift/example/example.rs index 885e55bc76423..1ef2aa5dd8ea4 100644 --- a/compiler/rustc_codegen_cranelift/example/example.rs +++ b/compiler/rustc_codegen_cranelift/example/example.rs @@ -149,7 +149,7 @@ pub fn array_as_slice(arr: &[u8; 3]) -> &[u8] { arr } -pub unsafe fn use_ctlz_nonzero(a: u16) -> u16 { +pub unsafe fn use_ctlz_nonzero(a: u16) -> u32 { intrinsics::ctlz_nonzero(a) } diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index a71217a554b57..c54574d801d3a 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -5,7 +5,7 @@ // Test that the simd_f{min,max} intrinsics produce the correct results. #![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] +#![allow(internal_features, non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index e45c16ee280a7..5e535ff62e173 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -627,7 +627,7 @@ pub mod intrinsics { pub fn min_align_of_val(val: *const T) -> usize; pub fn copy(src: *const T, dst: *mut T, count: usize); pub fn transmute(e: T) -> U; - pub fn ctlz_nonzero(x: T) -> T; + pub fn ctlz_nonzero(x: T) -> u32; #[rustc_safe_intrinsic] pub fn needs_drop() -> bool; #[rustc_safe_intrinsic] diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs index f15e48acc41e5..11a3e8fc72d8d 100644 --- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs +++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs @@ -1,4 +1,5 @@ #![feature(start, core_intrinsics, lang_items)] +#![allow(internal_features)] #![no_std] #[cfg_attr(unix, link(name = "c"))] diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index bad26947967dc..00e437d7e546a 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -4,7 +4,9 @@ #[cfg(target_arch = "aarch64")] use std::arch::aarch64::*; +#[cfg(target_arch = "aarch64")] use std::mem::transmute; +#[cfg(target_arch = "aarch64")] use std::simd::*; #[cfg(target_arch = "aarch64")] diff --git a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs index c965b34e13b90..407da94c0f092 100644 --- a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs +++ b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -8,7 +8,8 @@ fn main() { } fn run_coroutine() { - let mut coroutine = || { + let mut coroutine = #[coroutine] + || { yield; return; }; diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 2fee912e52ccf..90d4ab721daef 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,12 +1,14 @@ #![feature( core_intrinsics, coroutines, + stmt_expr_attributes, coroutine_trait, is_sorted, repr_simd, tuple_trait, unboxed_closures )] +#![allow(internal_features)] #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; @@ -122,9 +124,12 @@ fn main() { test_simd(); } - Box::pin(move |mut _task_context| { - yield (); - }) + Box::pin( + #[coroutine] + move |mut _task_context| { + yield (); + }, + ) .as_mut() .resume(0); diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch index 0e5e7cdfcdf1a..77716c5139978 100644 --- a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch +++ b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch @@ -11,7 +11,7 @@ diff --git a/src/report.rs b/src/report.rs index eeec614..f582867 100644 --- a/src/report.rs +++ b/src/report.rs -@@ -48,6 +48,12 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl +@@ -48,6 +48,15 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl // // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES @@ -19,6 +19,9 @@ index eeec614..f582867 100644 + if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" { + result.run = Link; + result.check = Pass(Link); ++ } else if test.test_name == "ui128" { ++ result.run == Check; ++ result.check = Pass(Check); + } + // END OF VENDOR RESERVED AREA diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 3e7da4e161f09..de340cf8c35cc 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-11" +channel = "nightly-2024-04-23" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 6363a0d59a4f2..6f346af25c6dd 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -7,11 +7,13 @@ mod returning; use std::borrow::Cow; use cranelift_codegen::ir::SigRef; +use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::TypeVisitableExt; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::Session; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index f428c4c7c0de0..e3d050df4cd1b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -2,12 +2,14 @@ use cranelift_codegen::ir::UserFuncName; use cranelift_codegen::CodegenError; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_module::ModuleError; use rustc_ast::InlineAsmOptions; use rustc_index::IndexVec; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::TypeVisitableExt; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use crate::constant::ConstantCx; @@ -823,7 +825,13 @@ fn codegen_stmt<'tcx>( }; let data = codegen_operand(fx, data); let meta = codegen_operand(fx, meta); - let ptr_val = CValue::pointer_from_data_and_meta(data, meta, layout); + assert!(data.layout().ty.is_unsafe_ptr()); + assert!(layout.ty.is_unsafe_ptr()); + let ptr_val = if meta.layout().is_zst() { + data.cast_pointer_to(layout) + } else { + CValue::by_val_pair(data.load_scalar(fx), meta.load_scalar(fx), layout) + }; lval.write_cvalue(fx, ptr_val); } Rvalue::Aggregate(ref kind, ref operands) => { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index cf0b065414d88..2a24d6150bd6e 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,8 +1,10 @@ use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_index::IndexVec; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, + self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; +use rustc_middle::ty::TypeFoldable; use rustc_span::source_map::Spanned; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index cb05c17ec2a88..cdf499a22f8dd 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -137,18 +137,23 @@ pub(crate) fn codegen_const_value<'tcx>( let alloc_id = prov.alloc_id(); let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { - let data_id = data_id_for_alloc_id( - &mut fx.constants_cx, - fx.module, - alloc_id, - alloc.inner().mutability, - ); - let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(local_data_id, format!("{:?}", alloc_id)); + if alloc.inner().len() == 0 { + assert_eq!(offset, Size::ZERO); + fx.bcx.ins().iconst(fx.pointer_type, alloc.inner().align.bytes() as i64) + } else { + let data_id = data_id_for_alloc_id( + &mut fx.constants_cx, + fx.module, + alloc_id, + alloc.inner().mutability, + ); + let local_data_id = + fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("{:?}", alloc_id)); + } + fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } GlobalAlloc::Function(instance) => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 32b9c824ded2f..78b3d5a58f4a2 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -7,7 +7,7 @@ use cranelift_codegen::binemit::CodeOffset; use cranelift_codegen::MachSrcLoc; use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{ - FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, + hygiene, FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, }; use crate::debuginfo::emit::address_for_func; @@ -63,11 +63,8 @@ impl DebugContext { function_span: Span, span: Span, ) -> (FileId, u64, u64) { - // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131 - // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site (when the macro is - // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = tcx.collapsed_debuginfo(span, function_span); + // Match behavior of `FunctionCx::adjusted_span_and_dbg_scope`. + let span = hygiene::walk_chain_collapsed(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let file_id = self.add_source_file(&file); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 5d943b5d99657..f0b78e5d7c674 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -19,7 +19,7 @@ use rustc_codegen_ssa::debuginfo::type_names; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_session::Session; -use rustc_span::{SourceFileHash, StableSourceFileId}; +use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}; use rustc_target::abi::call::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs index 27eabd8a0a616..65f4c67b21f13 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -2,7 +2,7 @@ use cranelift_module::{DataId, FuncId}; use cranelift_object::ObjectProduct; use gimli::SectionId; use object::write::{Relocation, StandardSegment}; -use object::{RelocationEncoding, SectionKind}; +use object::{RelocationEncoding, RelocationFlags, SectionKind}; use rustc_data_structures::fx::FxHashMap; use crate::debuginfo::{DebugReloc, DebugRelocName}; @@ -72,9 +72,11 @@ impl WriteDebugInfo for ObjectProduct { Relocation { offset: u64::from(reloc.offset), symbol, - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, + flags: RelocationFlags::Generic { + kind: reloc.kind, + encoding: RelocationEncoding::Generic, + size: reloc.size * 8, + }, addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, }, ) diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 6dbc3f191278d..929fa92596dc6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -6,6 +6,7 @@ use std::ffi::CString; use std::os::raw::{c_char, c_int}; use std::sync::{mpsc, Mutex, OnceLock}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 171ee88a11c75..28b92f730da34 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -2,6 +2,7 @@ use std::fmt::Write; +use cranelift_codegen::isa::CallConv; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_span::sym; use rustc_target::asm::*; @@ -785,9 +786,9 @@ fn call_inline_asm<'tcx>( for (offset, place) in outputs { let ty = if place.layout().ty.is_simd() { let (lane_count, lane_type) = place.layout().ty.simd_size_and_type(fx.tcx); - fx.clif_type(lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap() + asm_clif_type(fx, lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap() } else { - fx.clif_type(place.layout().ty).unwrap() + asm_clif_type(fx, place.layout().ty).unwrap() }; let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load( fx, @@ -797,3 +798,24 @@ fn call_inline_asm<'tcx>( place.write_cvalue(fx, CValue::by_val(value, place.layout())); } } + +fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { + match ty.kind() { + // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 + ty::Adt(adt, args) if Some(adt.did()) == fx.tcx.lang_items().maybe_uninit() => { + let fields = &adt.non_enum_variant().fields; + let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); + let ty::Adt(ty, args) = ty.kind() else { + unreachable!("expected first field of `MaybeUninit` to be an ADT") + }; + assert!( + ty.is_manually_drop(), + "expected first field of `MaybeUninit` to be `ManuallyDrop`" + ); + let fields = &ty.non_enum_variant().fields; + let ty = fields[FieldIdx::ZERO].ty(fx.tcx, args); + fx.clif_type(ty) + } + _ => fx.clif_type(ty), + } +} diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 0b213ff826969..79a90507fa2e1 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -26,6 +26,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; +use crate::cast::clif_intcast; use crate::prelude::*; fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { @@ -627,7 +628,8 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME trap on `ctlz_nonzero` with zero arg. let res = fx.bcx.ins().clz(val); - let res = CValue::by_val(res, arg.layout()); + let res = clif_intcast(fx, res, types::I32, false); + let res = CValue::by_val(res, ret.layout()); ret.write_cvalue(fx, res); } sym::cttz | sym::cttz_nonzero => { @@ -636,7 +638,8 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME trap on `cttz_nonzero` with zero arg. let res = fx.bcx.ins().ctz(val); - let res = CValue::by_val(res, arg.layout()); + let res = clif_intcast(fx, res, types::I32, false); + let res = CValue::by_val(res, ret.layout()); ret.write_cvalue(fx, res); } sym::ctpop => { @@ -644,7 +647,8 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = arg.load_scalar(fx); let res = fx.bcx.ins().popcnt(val); - let res = CValue::by_val(res, arg.layout()); + let res = clif_intcast(fx, res, types::I32, false); + let res = CValue::by_val(res, ret.layout()); ret.write_cvalue(fx, res); } sym::bitreverse => { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index d0ab64a558490..c9f84b6999718 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -87,21 +87,17 @@ mod prelude { AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value, }; - pub(crate) use cranelift_codegen::isa::{self, CallConv}; pub(crate) use cranelift_codegen::Context; - pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module}; pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub(crate) use rustc_index::Idx; - pub(crate) use rustc_middle::bug; pub(crate) use rustc_middle::mir::{self, *}; - pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; + pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, - TypeFoldable, TypeVisitableExt, UintTy, + self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy, }; - pub(crate) use rustc_span::{FileNameDisplayPreference, Span}; + pub(crate) use rustc_span::Span; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; pub(crate) use crate::abi::*; @@ -261,7 +257,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple { } } -fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { +fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 1abfded8b11f0..1f20ec42ddb3e 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,3 +1,4 @@ +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; use rustc_middle::ty::AssocKind; use rustc_middle::ty::GenericArg; diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 8d52fd9d7a8e4..dded6df7771df 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -2,6 +2,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::immediates::Offset32; +use cranelift_frontend::Variable; use rustc_middle::ty::FnSig; use crate::prelude::*; @@ -94,23 +95,6 @@ impl<'tcx> CValue<'tcx> { CValue(CValueInner::ByValPair(value, extra), layout) } - /// For `AggregateKind::RawPtr`, create a pointer from its parts. - /// - /// Panics if the `layout` is not a raw pointer. - pub(crate) fn pointer_from_data_and_meta( - data: CValue<'tcx>, - meta: CValue<'tcx>, - layout: TyAndLayout<'tcx>, - ) -> CValue<'tcx> { - assert!(layout.ty.is_unsafe_ptr()); - let inner = match (data.0, meta.0) { - (CValueInner::ByVal(p), CValueInner::ByVal(m)) => CValueInner::ByValPair(p, m), - (p @ CValueInner::ByVal(_), CValueInner::ByRef(..)) if meta.1.is_zst() => p, - _ => bug!("RawPtr operands {data:?} {meta:?}"), - }; - CValue(inner, layout) - } - pub(crate) fn layout(&self) -> TyAndLayout<'tcx> { self.1 } diff --git a/compiler/rustc_codegen_gcc/example/example.rs b/compiler/rustc_codegen_gcc/example/example.rs index 5878e8548d926..7c21b73b630e8 100644 --- a/compiler/rustc_codegen_gcc/example/example.rs +++ b/compiler/rustc_codegen_gcc/example/example.rs @@ -153,9 +153,10 @@ fn array_as_slice(arr: &[u8; 3]) -> &[u8] { arr } -unsafe fn use_ctlz_nonzero(a: u16) -> u16 { - intrinsics::ctlz_nonzero(a) -} +// FIXME: fix the intrinsic implementation to work with the new ->u32 signature +// unsafe fn use_ctlz_nonzero(a: u16) -> u32 { +// intrinsics::ctlz_nonzero(a) +// } fn ptr_as_usize(ptr: *const u8) -> usize { ptr as usize diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 4665009e191e6..a48c0a4450c29 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -420,7 +420,6 @@ pub fn panic(_msg: &'static str) -> ! { macro_rules! panic_const { ($($lang:ident = $message:expr,)+) => { - #[cfg(not(bootstrap))] pub mod panic_const { use super::*; @@ -593,7 +592,7 @@ pub mod intrinsics { pub fn min_align_of_val(val: *const T) -> usize; pub fn copy(src: *const T, dst: *mut T, count: usize); pub fn transmute(e: T) -> U; - pub fn ctlz_nonzero(x: T) -> T; + pub fn ctlz_nonzero(x: T) -> u32; #[rustc_safe_intrinsic] pub fn needs_drop() -> bool; #[rustc_safe_intrinsic] diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index ad69409eb6590..8ab8fcc525e5c 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -1,5 +1,5 @@ #![allow(internal_features)] -#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)] +#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)] #[cfg(feature="master")] #[cfg(target_arch="x86_64")] @@ -103,7 +103,7 @@ fn main() { test_simd(); } - Box::pin(move |mut _task_context| { + Box::pin(#[coroutine] move |mut _task_context| { yield (); }).as_mut().resume(0); diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index d353704fb75d8..23a5e5ff8730c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -898,26 +898,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.gcc_checked_binop(oop, typ, lhs, rhs) } - fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> { - // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. - // Ideally, we shouldn't need to do this check. - let aligned_type = if ty == self.cx.u128_type || ty == self.cx.i128_type { - ty - } else { - ty.get_aligned(align.bytes()) - }; + fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> { + let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes()); // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. self.stack_var_count.set(self.stack_var_count.get() + 1); self.current_func() .new_local( self.location, - aligned_type, + ty, &format!("stack_var_{}", self.stack_var_count.get()), ) .get_address(self.location) } - fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + fn dynamic_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index bee6bda007c3f..451e5258ebd19 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -531,7 +531,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // We instead thus allocate some scratch space... let scratch_size = cast.size(bx); let scratch_align = cast.align(bx); - let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align); + let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); // ... where we first store the value... @@ -1223,7 +1223,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>( tcx, ty::Binder::dummy(tcx.mk_fn_sig( iter::once(i8p), - Ty::new_unit(tcx), + tcx.types.unit, false, rustc_hir::Unsafety::Unsafe, Abi::Rust, @@ -1234,7 +1234,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>( tcx, ty::Binder::dummy(tcx.mk_fn_sig( [i8p, i8p].iter().cloned(), - Ty::new_unit(tcx), + tcx.types.unit, false, rustc_hir::Unsafety::Unsafe, Abi::Rust, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 6039a4aaf013e..0c7cffbe7308b 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -18,7 +18,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span, Symbol}; -use rustc_target::abi::Align; +use rustc_target::abi::{Align, Size}; use crate::builder::Builder; #[cfg(not(feature = "master"))] @@ -558,7 +558,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let ze = bx.zext(result, bx.type_ix(expected_bytes * 8)); // Convert the integer to a byte array - let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE); + let ptr = bx.alloca(Size::from_bytes(expected_bytes), Align::ONE); bx.store(ze, ptr, Align::ONE); let array_ty = bx.type_array(bx.type_i8(), expected_bytes); let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty)); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 345c22394f21a..3f2fadce9e4d5 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -23,7 +23,6 @@ trusted_len, hash_raw_entry )] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index c0b43b778979e..123aef0f31076 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -2,6 +2,7 @@ use crate::attributes; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Attribute, AttributePlace}; +use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -227,7 +228,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // when passed by value, making it larger. let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes()); // Allocate some scratch space... - let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); + let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); // ...store the value... bx.store(val, llscratch, scratch_align); @@ -425,6 +426,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()), ); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); + if cx.sess().opts.optimize != config::OptLevel::No + && llvm_util::get_version() >= (18, 0, 0) + { + attributes::apply_to_llfn( + llfn, + llvm::AttributePlace::Argument(i), + &[ + llvm::AttributeKind::Writable.create_attr(cx.llcx), + llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx), + ], + ); + } } PassMode::Cast { cast, pad_i32: _ } => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4c2bdb2f5ec27..5c8f358d03a1f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -27,6 +27,7 @@ use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use std::borrow::Cow; +use std::ffi::CString; use std::iter; use std::ops::Deref; use std::ptr; @@ -468,9 +469,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { val } - fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value { + fn alloca(&mut self, size: Size, align: Align) -> &'ll Value { let mut bx = Builder::with_cx(self.cx); bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); + let ty = self.cx().type_array(self.cx().type_i8(), size.bytes()); unsafe { let alloca = llvm::LLVMBuildAlloca(bx.llbuilder, ty, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); @@ -478,10 +480,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn byte_array_alloca(&mut self, len: &'ll Value, align: Align) -> &'ll Value { + fn dynamic_alloca(&mut self, size: &'ll Value, align: Align) -> &'ll Value { unsafe { let alloca = - llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), len, UNNAMED); + llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), size, UNNAMED); llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); alloca } @@ -1708,7 +1710,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn_name: &'ll Value, hash: &'ll Value, bitmap_bytes: &'ll Value, - ) -> &'ll Value { + max_decision_depth: u32, + ) -> Vec<&'ll Value> { debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes); assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later"); @@ -1721,6 +1724,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let args = &[fn_name, hash, bitmap_bytes]; let args = self.check_call("call", llty, llfn, args); + let mut cond_bitmaps = vec![]; + unsafe { let _ = llvm::LLVMRustBuildCall( self.llbuilder, @@ -1732,17 +1737,22 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { 0 as c_uint, ); // Create condition bitmap named `mcdc.addr`. - let mut bx = Builder::with_cx(self.cx); - bx.position_at_start(llvm::LLVMGetFirstBasicBlock(self.llfn())); - let cond_bitmap = { - let alloca = - llvm::LLVMBuildAlloca(bx.llbuilder, bx.cx.type_i32(), c"mcdc.addr".as_ptr()); - llvm::LLVMSetAlignment(alloca, 4); - alloca - }; - bx.store(self.const_i32(0), cond_bitmap, self.tcx().data_layout.i32_align.abi); - cond_bitmap + for i in 0..=max_decision_depth { + let mut bx = Builder::with_cx(self.cx); + bx.position_at_start(llvm::LLVMGetFirstBasicBlock(self.llfn())); + + let name = CString::new(format!("mcdc.addr.{i}")).unwrap(); + let cond_bitmap = { + let alloca = + llvm::LLVMBuildAlloca(bx.llbuilder, bx.cx.type_i32(), name.as_ptr()); + llvm::LLVMSetAlignment(alloca, 4); + alloca + }; + bx.store(self.const_i32(0), cond_bitmap, self.tcx().data_layout.i32_align.abi); + cond_bitmaps.push(cond_bitmap); + } } + cond_bitmaps } pub(crate) fn mcdc_tvbitmap_update( diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a62dfe132047e..9e85c2d88f9b4 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -260,7 +260,8 @@ impl<'ll> CodegenCx<'ll, '_> { #[instrument(level = "debug", skip(self, llty))] pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value { - if let Some(&g) = self.instances.borrow().get(&Instance::mono(self.tcx, def_id)) { + let instance = Instance::mono(self.tcx, def_id); + if let Some(&g) = self.instances.borrow().get(&instance) { trace!("used cached value"); return g; } @@ -273,7 +274,7 @@ impl<'ll> CodegenCx<'ll, '_> { statics defined in the same CGU, but did not for `{def_id:?}`" ); - let sym = self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name; + let sym = self.tcx.symbol_name(instance).name; let fn_attrs = self.tcx.codegen_fn_attrs(def_id); debug!(?sym, ?fn_attrs); @@ -363,7 +364,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } - self.instances.borrow_mut().insert(Instance::mono(self.tcx, def_id), g); + self.instances.borrow_mut().insert(instance, g); g } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 085ce15d81fe8..679c6e1a2ff83 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -30,7 +30,7 @@ pub struct CrateCoverageContext<'ll, 'tcx> { pub(crate) function_coverage_map: RefCell, FunctionCoverageCollector<'tcx>>>, pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>, - pub(crate) mcdc_condition_bitmap_map: RefCell, &'ll llvm::Value>>, + pub(crate) mcdc_condition_bitmap_map: RefCell, Vec<&'ll llvm::Value>>>, } impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { @@ -49,9 +49,20 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { } /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is called condition bitmap. - /// This value is named `mcdc.addr` (same as clang) and is a 32-bit integer. - fn try_get_mcdc_condition_bitmap(&self, instance: &Instance<'tcx>) -> Option<&'ll llvm::Value> { - self.mcdc_condition_bitmap_map.borrow().get(instance).copied() + /// In order to handle nested decisions, several condition bitmaps can be + /// allocated for a function body. + /// These values are named `mcdc.addr.{i}` and are a 32-bit integers. + /// They respectively hold the condition bitmaps for decisions with a depth of `i`. + fn try_get_mcdc_condition_bitmap( + &self, + instance: &Instance<'tcx>, + decision_depth: u16, + ) -> Option<&'ll llvm::Value> { + self.mcdc_condition_bitmap_map + .borrow() + .get(instance) + .and_then(|bitmap_map| bitmap_map.get(decision_depth as usize)) + .copied() // Dereference Option<&&Value> to Option<&Value> } } @@ -143,7 +154,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { CoverageKind::ExpressionUsed { id } => { func_coverage.mark_expression_id_seen(id); } - CoverageKind::CondBitmapUpdate { id, value, .. } => { + CoverageKind::CondBitmapUpdate { id, value, decision_depth } => { drop(coverage_map); assert_ne!( id.as_u32(), @@ -151,7 +162,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { "ConditionId of evaluated conditions should never be zero" ); let cond_bitmap = coverage_context - .try_get_mcdc_condition_bitmap(&instance) + .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for updating"); let cond_loc = bx.const_i32(id.as_u32() as i32 - 1); let bool_value = bx.const_bool(value); @@ -159,10 +170,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let hash = bx.const_u64(function_coverage_info.function_source_hash); bx.mcdc_condbitmap_update(fn_name, hash, cond_loc, cond_bitmap, bool_value); } - CoverageKind::TestVectorBitmapUpdate { bitmap_idx } => { + CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { drop(coverage_map); let cond_bitmap = coverage_context - .try_get_mcdc_condition_bitmap(&instance) + .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap"); let bitmap_bytes = bx.tcx().coverage_ids_info(instance.def).mcdc_bitmap_bytes; assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range"); @@ -195,7 +206,8 @@ fn ensure_mcdc_parameters<'ll, 'tcx>( let fn_name = bx.get_pgo_func_name_var(instance); let hash = bx.const_u64(function_coverage_info.function_source_hash); let bitmap_bytes = bx.const_u32(function_coverage_info.mcdc_bitmap_bytes); - let cond_bitmap = bx.mcdc_parameters(fn_name, hash, bitmap_bytes); + let max_decision_depth = function_coverage_info.mcdc_max_decision_depth; + let cond_bitmap = bx.mcdc_parameters(fn_name, hash, bitmap_bytes, max_decision_depth as u32); bx.coverage_context() .expect("already checked above") .mcdc_condition_bitmap_map diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 1aec65cf94900..e521d5e259caa 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -5,6 +5,7 @@ use rustc_data_structures::{ fx::FxHashMap, stable_hasher::{HashStable, StableHasher}, }; +use rustc_macros::HashStable; use rustc_middle::{ bug, ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}, @@ -23,6 +24,8 @@ use crate::{ use super::{unknown_file_metadata, SmallVec, UNKNOWN_LINE_NUMBER}; mod private { + use rustc_macros::HashStable; + // This type cannot be constructed outside of this module because // it has a private field. We make use of this in order to prevent // `UniqueTypeId` from being constructed directly, without asserting diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2bed7c1bd1ccf..56550dbfa4b8b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, Span, Symbol}; -use rustc_target::abi::{self, Align, HasDataLayout, Primitive}; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; @@ -315,25 +315,32 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { Some((width, signed)) => match name { sym::ctlz | sym::cttz => { let y = self.const_bool(false); - self.call_intrinsic( + let ret = self.call_intrinsic( &format!("llvm.{name}.i{width}"), &[args[0].immediate(), y], - ) + ); + + self.intcast(ret, llret_ty, false) } sym::ctlz_nonzero => { let y = self.const_bool(true); let llvm_name = &format!("llvm.ctlz.i{width}"); - self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) + let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + self.intcast(ret, llret_ty, false) } sym::cttz_nonzero => { let y = self.const_bool(true); let llvm_name = &format!("llvm.cttz.i{width}"); - self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) + let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]); + self.intcast(ret, llret_ty, false) + } + sym::ctpop => { + let ret = self.call_intrinsic( + &format!("llvm.ctpop.i{width}"), + &[args[0].immediate()], + ); + self.intcast(ret, llret_ty, false) } - sym::ctpop => self.call_intrinsic( - &format!("llvm.ctpop.i{width}"), - &[args[0].immediate()], - ), sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op @@ -355,6 +362,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { // rotate = funnel shift with first two args the same let llvm_name = &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width); + + // llvm expects shift to be the same type as the values, but rust always uses `u32` + let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); + self.call_intrinsic(llvm_name, &[val, val, raw_shift]) } sym::saturating_add | sym::saturating_sub => { @@ -638,8 +649,9 @@ fn codegen_msvc_try<'ll>( // } // // More information can be found in libstd's seh.rs implementation. + let ptr_size = bx.tcx().data_layout.pointer_size; let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let slot = bx.alloca(bx.type_ptr(), ptr_align); + let slot = bx.alloca(ptr_size, ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); @@ -909,15 +921,14 @@ fn codegen_emcc_try<'ll>( // We need to pass two values to catch_func (ptr and is_rust_panic), so // create an alloca and pass a pointer to that. + let ptr_size = bx.tcx().data_layout.pointer_size; let ptr_align = bx.tcx().data_layout.pointer_align.abi; let i8_align = bx.tcx().data_layout.i8_align.abi; - let catch_data_type = bx.type_struct(&[bx.type_ptr(), bx.type_bool()], false); - let catch_data = bx.alloca(catch_data_type, ptr_align); - let catch_data_0 = - bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(0)]); - bx.store(ptr, catch_data_0, ptr_align); - let catch_data_1 = - bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(1)]); + // Required in order for there to be no padding between the fields. + assert!(i8_align <= ptr_align); + let catch_data = bx.alloca(2 * ptr_size, ptr_align); + bx.store(ptr, catch_data, ptr_align); + let catch_data_1 = bx.inbounds_ptradd(catch_data, bx.const_usize(ptr_size.bytes())); bx.store(is_rust_panic, catch_data_1, i8_align); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); @@ -973,7 +984,7 @@ fn get_rust_try_fn<'ll, 'tcx>( tcx, ty::Binder::dummy(tcx.mk_fn_sig( [i8p], - Ty::new_unit(tcx), + tcx.types.unit, false, hir::Unsafety::Unsafe, Abi::Rust, @@ -984,7 +995,7 @@ fn get_rust_try_fn<'ll, 'tcx>( tcx, ty::Binder::dummy(tcx.mk_fn_sig( [i8p, i8p], - Ty::new_unit(tcx), + tcx.types.unit, false, hir::Unsafety::Unsafe, Abi::Rust, @@ -1363,7 +1374,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8)); // Convert the integer to a byte array - let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE); + let ptr = bx.alloca(Size::from_bytes(expected_bytes), Align::ONE); bx.store(ze, ptr, Align::ONE); let array_ty = bx.type_array(bx.type_i8(), expected_bytes); return Ok(bx.load(array_ty, ptr, Align::ONE)); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index c84461e53eb1b..1cecf682e5db6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -15,8 +15,6 @@ #![feature(let_chains)] #![feature(impl_trait_in_assoc_type)] -#[macro_use] -extern crate rustc_macros; #[macro_use] extern crate tracing; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a10dc61967ede..7a34e21628dc6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -200,6 +200,8 @@ pub enum AttributeKind { AllocAlign = 39, SanitizeSafeStack = 40, FnRetThunkExtern = 41, + Writable = 42, + DeadOnUnwind = 43, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b458f325b7373..1f691d14c5320 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -8,6 +8,7 @@ use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME}; +use rustc_middle::bug; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 85fcc4f4f4046..f85056f8ad410 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -12,6 +12,7 @@ use std::{env, mem, str}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; +use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ab1bc0b6cd2eb..264a98844ad67 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -16,6 +16,7 @@ use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; +use rustc_middle::bug; use rustc_session::Session; use rustc_span::sym; use rustc_target::abi::Endian; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b19f52182b650..0e335bf00cf05 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -6,6 +6,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE} use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, @@ -363,6 +364,24 @@ fn exported_symbols_provider_local( }, )); } + MonoItem::Fn(Instance { + def: InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)), + args, + }) => { + // A little sanity-check + debug_assert_eq!( + args.non_erasable_generics(tcx, def_id).skip(1).next(), + Some(GenericArgKind::Type(ty)) + ); + symbols.push(( + ExportedSymbol::AsyncDropGlueCtorShim(ty), + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); + } _ => { // Any other symbols don't qualify for sharing } @@ -385,6 +404,7 @@ fn upstream_monomorphizations_provider( let mut instances: DefIdMap> = Default::default(); let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); + let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn(); for &cnum in cnums.iter() { for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { @@ -399,6 +419,18 @@ fn upstream_monomorphizations_provider( continue; } } + ExportedSymbol::AsyncDropGlueCtorShim(ty) => { + if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id { + ( + async_drop_in_place_fn_def_id, + tcx.mk_args(&[tcx.lifetimes.re_erased.into(), ty.into()]), + ) + } else { + // `drop_in_place` in place does not exist, don't try + // to use it. + continue; + } + } ExportedSymbol::NonGeneric(..) | ExportedSymbol::ThreadLocalShim(..) | ExportedSymbol::NoDefId(..) => { @@ -534,6 +566,13 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( Instance::resolve_drop_in_place(tcx, ty), instantiating_crate, ), + ExportedSymbol::AsyncDropGlueCtorShim(ty) => { + rustc_symbol_mangling::symbol_name_for_instance_in_crate( + tcx, + Instance::resolve_async_drop_in_place(tcx, ty), + instantiating_crate, + ) + } ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), } } @@ -582,6 +621,9 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( // DropGlue always use the Rust calling convention and thus follow the target's default // symbol decoration scheme. ExportedSymbol::DropGlue(..) => None, + // AsyncDropGlueCtorShim always use the Rust calling convention and thus follow the + // target's default symbol decoration scheme. + ExportedSymbol::AsyncDropGlueCtorShim(..) => None, // NoDefId always follow the target's default symbol decoration scheme. ExportedSymbol::NoDefId(..) => None, // ThreadLocalShim always follow the target's default symbol decoration scheme. diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c4f062405bb5c..53ba0da7d0490 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -26,6 +26,7 @@ use rustc_incremental::{ }; use rustc_metadata::fs::copy_to_stdout; use rustc_metadata::EncodedMetadata; +use rustc_middle::bug; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::exported_symbols::SymbolExportInfo; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 930b9b8c0db24..358c24bfb823c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -24,6 +24,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_metadata::EncodedMetadata; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols; @@ -508,7 +509,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let ptr_size = bx.tcx().data_layout.pointer_size; let ptr_align = bx.tcx().data_layout.pointer_align.abi; let arg_argc = bx.const_int(cx.type_isize(), 2); - let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), ptr_align); + let arg_argv = bx.alloca(2 * ptr_size, ptr_align); bx.store(param_handle, arg_argv, ptr_align); let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes())); bx.store(param_system_table, arg_argv_el1, ptr_align); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 9c9e134f0337e..c28b0d644e675 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -435,7 +435,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::repr => { codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() && let [item] = items.as_slice() - && let Some((sym::align, literal)) = item.name_value_literal() + && let Some((sym::align, literal)) = item.singleton_lit_list() { rustc_attr::parse_alignment(&literal.kind) .map_err(|msg| { diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index b41739867c7dc..e4a36b3f59187 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -4,6 +4,7 @@ use rustc_hir::LangItem; use rustc_middle::mir; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, layout::TyAndLayout, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; use crate::traits::*; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 5f0dcf9510f9d..e9c7606dc5a82 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -16,6 +16,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability}; +use rustc_middle::bug; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index b843d1bdf2350..ed6a0c2441061 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -431,7 +431,6 @@ pub struct ProcessingDymutilFailed { #[derive(Diagnostic)] #[diag(codegen_ssa_unable_to_run_dsymutil)] -#[note] pub struct UnableToRunDsymutil { pub error: Error, } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 80fe7e0bb7865..4eb24d71009aa 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -4,7 +4,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] @@ -16,12 +15,8 @@ //! The backend-agnostic functions of this crate use functions defined in various traits that //! have to be implemented by each backend. -#[macro_use] -extern crate rustc_macros; #[macro_use] extern crate tracing; -#[macro_use] -extern crate rustc_middle; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; @@ -29,6 +24,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::CrateNum; +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 4f7dc9968a13c..23036e9bea022 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -1,5 +1,6 @@ use crate::traits::*; +use rustc_middle::bug; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::config::Lto; use rustc_symbol_mangling::typeid_for_trait_ref; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c1de9b76fe734..09ae7cf64109b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::{bug, span_bug}; pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 452398e6d8285..be5458523d1ca 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -17,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTermi use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::config::OptLevel; use rustc_span::{source_map::Spanned, sym, Span}; @@ -835,7 +836,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def = instance.map(|i| i.def); - if let Some(ty::InstanceDef::DropGlue(_, None)) = def { + if let Some( + ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None), + ) = def + { // Empty drop glue; a no-op. let target = target.unwrap(); return helper.funclet_br(self, bx, target, mergeable_succ); @@ -1514,7 +1518,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // when passed by value, making it larger. let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes()); // Allocate some scratch space... - let llscratch = bx.alloca(bx.cast_backend_type(cast), scratch_align); + let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); // ...memcpy the value... bx.memcpy( diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index c6260d3591618..dba5fbefd8a79 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -5,6 +5,7 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_target::abi::Abi; use super::FunctionCx; diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index a5fd82a305414..50bf1ef61f3a4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,16 +1,16 @@ use crate::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Instance; use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{hygiene, BytePos, Span}; use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; @@ -220,26 +220,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, source_info: mir::SourceInfo, ) -> Option<(Bx::DIScope, Option, Span)> { - let span = self.adjust_span_for_debugging(source_info.span); let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; + let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span); Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) } - /// In order to have a good line stepping behavior in debugger, we overwrite debug - /// locations of macro expansions with that of the outermost expansion site (when the macro is - /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - fn adjust_span_for_debugging(&self, span: Span) -> Span { - // Bail out if debug info emission is not enabled. - if self.debug_context.is_none() { - return span; - } - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - // Use span of the outermost expansion site, while keeping the original lexical scope. - self.cx.tcx().collapsed_debuginfo(span, self.mir.span) - } - fn spill_operand_to_stack( operand: OperandRef<'tcx, Bx::Value>, name: Option, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index eb14a90412d5f..2e008460798f8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -9,6 +9,7 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{sym, Span}; use rustc_target::abi::{ diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index b98e90b5cde04..0064c16f5d9f6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -8,6 +8,7 @@ use rustc_middle::mir::traversal; use rustc_middle::mir::UnwindTerminateReason; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::{bug, span_bug}; use rustc_target::abi::call::{FnAbi, PassMode}; use std::iter; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 9cf64e2d67682..38f77f2e646fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -5,6 +5,7 @@ use crate::size_of_val; use crate::traits::*; use crate::MemFlags; +use rustc_middle::bug; use rustc_middle::mir::interpret::{alloc_range, Pointer, Scalar}; use rustc_middle::mir::{self, ConstValue}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; @@ -327,7 +328,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llfield_ty = bx.cx().backend_type(field); // Can't bitcast an aggregate, so round trip through memory. - let llptr = bx.alloca(llfield_ty, field.align.abi); + let llptr = bx.alloca(field.size, field.align.abi); bx.store(*llval, llptr, field.align.abi); *llval = bx.load(llfield_ty, llptr, field.align.abi); } @@ -470,7 +471,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let align_minus_1 = bx.sub(align, one); let size_extra = bx.add(size, align_minus_1); let min_align = Align::ONE; - let alloca = bx.byte_array_alloca(size_extra, min_align); + let alloca = bx.dynamic_alloca(size_extra, min_align); let address = bx.ptrtoint(alloca, bx.type_isize()); let neg_address = bx.neg(address); let offset = bx.and(neg_address, align_minus_1); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 90627da579e7c..870a105c61d6f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -5,6 +5,7 @@ use crate::common::IntPredicate; use crate::size_of_val; use crate::traits::*; +use rustc_middle::bug; use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; @@ -81,7 +82,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { align: Align, ) -> Self { assert!(layout.is_sized(), "tried to statically allocate unsized place"); - let tmp = bx.alloca(bx.cx().backend_type(layout), align); + let tmp = bx.alloca(layout.size, align); Self::new_sized_aligned(tmp, layout, align) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7823d4c249a84..4e7d251a2e928 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,11 +8,11 @@ use crate::traits::*; use crate::MemFlags; use rustc_hir as hir; -use rustc_middle::mir; -use rustc_middle::mir::{AggregateKind, Operand}; +use rustc_middle::mir::{self, AggregateKind, Operand}; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, FIRST_VARIANT}; diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 2188eeae42686..a0429022587ce 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,5 +1,5 @@ -use rustc_middle::mir; -use rustc_middle::mir::NonDivergingIntrinsic; +use rustc_middle::mir::{self, NonDivergingIntrinsic}; +use rustc_middle::span_bug; use rustc_session::config::OptLevel; use super::FunctionCx; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index df564f705bc73..40921c2932fa9 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -5,6 +5,7 @@ use rustc_hir as hir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::span_bug; use rustc_middle::ty; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::Instance; diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index c250cc2682323..032699f1fa15a 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -5,6 +5,7 @@ use crate::common::IntPredicate; use crate::meth; use crate::traits::*; use rustc_hir::LangItem; +use rustc_middle::bug; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::WrappingRange; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 241b0a15f7872..bcddfe9fb9cb0 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,6 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9191618c064be..51b22bfaf2558 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -144,8 +144,8 @@ pub trait BuilderMethods<'a, 'tcx>: } fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; - fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; - fn byte_array_alloca(&mut self, len: Self::Value, align: Align) -> Self::Value; + fn alloca(&mut self, size: Size, align: Align) -> Self::Value; + fn dynamic_alloca(&mut self, size: Self::Value, align: Align) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 34d9e75036f8f..ccb35629a829d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -3,6 +3,7 @@ use super::Backend; use super::HasCodegen; use crate::common::TypeKind; use crate::mir::place::PlaceRef; +use rustc_middle::bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f6937dc145d5b..b79d7441acac7 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -82,12 +82,6 @@ const_eval_double_storage_live = const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method -const_eval_dyn_call_vtable_mismatch = - `dyn` call on a pointer whose vtable does not match its type - -const_eval_dyn_star_call_vtable_mismatch = - `dyn*` call on a pointer whose vtable does not match its type - const_eval_error = {$error_kind -> [static] could not evaluate static initializer [const] evaluation of constant value failed @@ -192,6 +186,8 @@ const_eval_invalid_uninit_bytes_unknown = const_eval_invalid_vtable_pointer = using {$pointer} as vtable pointer but it does not point to a vtable +const_eval_invalid_vtable_trait = + using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected const_eval_live_drop = destructor of `{$dropped_ty}` cannot be evaluated at compile-time @@ -401,9 +397,6 @@ const_eval_unterminated_c_string = const_eval_unwind_past_top = unwinding past the topmost frame of the stack -const_eval_upcast_mismatch = - upcast on a pointer whose vtable does not match its type - ## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. ## (We'd love to sort this differently to make that more clear but tidy won't let us...) const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant @@ -450,6 +443,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer +const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}` const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_validation_null_box = {$front_matter}: encountered a null box diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index ba2e2a1e3539a..7b6828c6e1828 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -46,6 +46,9 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine { type MemoryKind = !; const PANIC_ON_ALLOC_FAIL: bool = true; + // We want to just eval random consts in the program, so `eval_mir_const` can fail. + const ALL_CONSTS_ARE_PRECHECKED: bool = false; + #[inline(always)] fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { false // no reason to enforce alignment diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index a60cedd6500d5..90d4f1168e4fd 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -498,6 +498,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidTag(_) => const_eval_invalid_tag, InvalidFunctionPointer(_) => const_eval_invalid_function_pointer, InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer, + InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait, InvalidStr(_) => const_eval_invalid_str, InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown, InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes, @@ -537,6 +538,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { | DeadLocal | UninhabitedEnumVariantWritten(_) | UninhabitedEnumVariantRead(_) => {} + BoundsCheckFailed { len, index } => { diag.arg("len", len); diag.arg("index", index); @@ -544,6 +546,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { diag.arg("pointer", ptr); } + InvalidVTableTrait { expected_trait, vtable_trait } => { + diag.arg("expected_trait", expected_trait.to_string()); + diag.arg( + "vtable_trait", + vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), + ); + } PointerUseAfterFree(alloc_id, msg) => { diag.arg("alloc_id", alloc_id) .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); @@ -634,6 +643,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, Uninit { .. } => const_eval_validation_uninit, InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, + InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait, InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { const_eval_validation_invalid_box_slice_meta } @@ -773,6 +783,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { DanglingPtrNoProvenance { pointer, .. } => { err.arg("pointer", pointer); } + InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => { + err.arg("ref_trait", ref_trait.to_string()); + err.arg( + "vtable_trait", + vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), + ); + } NullPtr { .. } | PtrToStatic { .. } | ConstRefToMutable diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9447d18fe8c93..76e59ea90559f 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -393,6 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = self.read_immediate(src)?; if data_a.principal() == data_b.principal() { // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables. + // (But currently mismatching vtables violate the validity invariant so UB is triggered anyway.) return self.write_immediate(*val, dest); } let (old_data, old_vptr) = val.to_scalar_pair(); @@ -400,7 +401,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_vptr = old_vptr.to_pointer(self)?; let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; if old_trait != data_a.principal() { - throw_ub_custom!(fluent::const_eval_upcast_mismatch); + throw_ub!(InvalidVTableTrait { + expected_trait: data_a, + vtable_trait: old_trait, + }); } let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 62d169db628bf..126d64329f815 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -822,15 +822,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.stack_mut().push(frame); // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). - if M::POST_MONO_CHECKS { - for &const_ in &body.required_consts { - let c = self - .instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; - c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| { - err.emit_note(*self.tcx); - err - })?; - } + for &const_ in &body.required_consts { + let c = + self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; + c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| { + err.emit_note(*self.tcx); + err + })?; } // done @@ -1181,8 +1179,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| { - // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. - // Are we not always populating `required_consts`? + if M::ALL_CONSTS_ARE_PRECHECKED && !matches!(err, ErrorHandled::TooGeneric(..)) { + // Looks like the const is not captued by `required_consts`, that's bad. + bug!("interpret const eval failure of {val:?} which is not in required_consts"); + } err.emit_note(*ecx.tcx); err })?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 63c709d8aedd6..4d37c3c22cd7c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -173,7 +173,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ty = instance_args.type_at(0); let layout = self.layout_of(ty)?; let val = self.read_scalar(&args[0])?; - let out_val = self.numeric_intrinsic(intrinsic_name, val, layout)?; + + let out_val = self.numeric_intrinsic(intrinsic_name, val, layout, dest.layout)?; self.write_scalar(out_val, dest)?; } sym::saturating_add | sym::saturating_sub => { @@ -200,12 +201,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::rotate_left | sym::rotate_right => { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) - let layout = self.layout_of(instance_args.type_at(0))?; + let layout_val = self.layout_of(instance_args.type_at(0))?; let val = self.read_scalar(&args[0])?; - let val_bits = val.to_bits(layout.size)?; + let val_bits = val.to_bits(layout_val.size)?; + + let layout_raw_shift = self.layout_of(self.tcx.types.u32)?; let raw_shift = self.read_scalar(&args[1])?; - let raw_shift_bits = raw_shift.to_bits(layout.size)?; - let width_bits = u128::from(layout.size.bits()); + let raw_shift_bits = raw_shift.to_bits(layout_raw_shift.size)?; + + let width_bits = u128::from(layout_val.size.bits()); let shift_bits = raw_shift_bits % width_bits; let inv_shift_bits = (width_bits - shift_bits) % width_bits; let result_bits = if intrinsic_name == sym::rotate_left { @@ -213,8 +217,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { (val_bits >> shift_bits) | (val_bits << inv_shift_bits) }; - let truncated_bits = self.truncate(result_bits, layout); - let result = Scalar::from_uint(truncated_bits, layout.size); + let truncated_bits = self.truncate(result_bits, layout_val); + let result = Scalar::from_uint(truncated_bits, layout_val.size); self.write_scalar(result, dest)?; } sym::copy => { @@ -472,6 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { name: Symbol, val: Scalar, layout: TyAndLayout<'tcx>, + ret_layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Scalar> { assert!(layout.ty.is_integral(), "invalid type for numeric intrinsic: {}", layout.ty); let bits = val.to_bits(layout.size)?; @@ -483,11 +488,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra, sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra, - sym::bswap => (bits << extra).swap_bytes(), - sym::bitreverse => (bits << extra).reverse_bits(), + sym::bswap => { + assert_eq!(layout, ret_layout); + (bits << extra).swap_bytes() + } + sym::bitreverse => { + assert_eq!(layout, ret_layout); + (bits << extra).reverse_bits() + } _ => bug!("not a numeric intrinsic: {}", name), }; - Ok(Scalar::from_uint(bits_out, layout.size)) + Ok(Scalar::from_uint(bits_out, ret_layout.size)) } pub fn exact_div( diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 7617cb57b3cd4..8bc569bed54c5 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -140,8 +140,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Should the machine panic on allocation failures? const PANIC_ON_ALLOC_FAIL: bool; - /// Should post-monomorphization checks be run when a stack frame is pushed? - const POST_MONO_CHECKS: bool = true; + /// Determines whether `eval_mir_constant` can never fail because all required consts have + /// already been checked before. + const ALL_CONSTS_ARE_PRECHECKED: bool = true; /// Whether memory accesses should be alignment-checked. fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 7ede90ad13f1d..7d7b421f86935 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -18,6 +18,7 @@ mod util; mod validity; mod visitor; +#[doc(no_inline)] pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup}; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 8364a5a8d186a..e5241f1ba19e1 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -1020,16 +1020,20 @@ where pub(super) fn unpack_dyn_trait( &self, mplace: &MPlaceTy<'tcx, M::Provenance>, + expected_trait: &'tcx ty::List>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer>)> { assert!( matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)), "`unpack_dyn_trait` only makes sense on `dyn*` types" ); let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; + let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?; + if expected_trait.principal() != vtable_trait { + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + } // This is a kind of transmute, from a place with unsized type and metadata to // a place with sized type and no metadata. + let layout = self.layout_of(ty)?; let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout }; Ok((mplace, vtable)) @@ -1040,6 +1044,7 @@ where pub(super) fn unpack_dyn_star>( &self, val: &P, + expected_trait: &'tcx ty::List>, ) -> InterpResult<'tcx, (P, Pointer>)> { assert!( matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), @@ -1048,10 +1053,12 @@ where let data = self.project_field(val, 0)?; let vtable = self.project_field(val, 1)?; let vtable = self.read_pointer(&vtable.to_op(self)?)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; + let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?; + if expected_trait.principal() != vtable_trait { + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + } + // `data` is already the right thing but has the wrong type. So we transmute it. let layout = self.layout_of(ty)?; - // `data` is already the right thing but has the wrong type. So we transmute it, by - // projecting with offset 0. let data = data.transmute(layout, self)?; Ok((data, vtable)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c0e27e86d500a..9c31532a9ce49 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -558,6 +558,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::FnPtrAddrShim(..) | ty::InstanceDef::ThreadLocalShim(..) + | ty::InstanceDef::AsyncDropGlueCtorShim(..) | ty::InstanceDef::Item(_) => { // We need MIR for this fn let Some((body, instance)) = M::find_mir_or_eval_fn( @@ -802,11 +803,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() { - let (recv, vptr) = self.unpack_dyn_star(&receiver_place)?; - let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; - if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_star_call_vtable_mismatch); - } + let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?; + let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?; (vptr, dyn_ty, recv.ptr()) } else { @@ -828,7 +826,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_call_vtable_mismatch); + throw_ub!(InvalidVTableTrait { + expected_trait: data, + vtable_trait: dyn_trait, + }); } // It might be surprising that we use a pointer as the receiver even if this @@ -938,13 +939,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let place = self.force_allocation(place)?; let place = match place.layout.ty.kind() { - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { // Dropping a trait object. Need to find actual drop fn. - self.unpack_dyn_trait(&place)?.0 + self.unpack_dyn_trait(&place, data)?.0 } - ty::Dynamic(_, _, ty::DynStar) => { + ty::Dynamic(data, _, ty::DynStar) => { // Dropping a `dyn*`. Need to find actual drop fn. - self.unpack_dyn_star(&place)?.0 + self.unpack_dyn_star(&place, data)?.0 } _ => { debug_assert_eq!( diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b8a1733e45ad6..14566719ccd72 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -339,16 +339,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind() { - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; // Make sure it is a genuine vtable pointer. - let (_ty, _trait) = try_validation!( + let (_dyn_ty, dyn_trait) = try_validation!( self.ecx.get_ptr_vtable(vtable), self.path, Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => InvalidVTablePtr { value: format!("{vtable}") } ); - // FIXME: check if the type/trait match what ty::Dynamic says? + // Make sure it is for the right trait. + if dyn_trait != data.principal() { + throw_validation_failure!( + self.path, + InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait } + ); + } } ty::Slice(..) | ty::Str => { let _len = meta.unwrap_meta().to_target_usize(self.ecx)?; @@ -933,7 +939,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } } _ => { - self.walk_value(op)?; // default handler + // default handler + try_validation!( + self.walk_value(op), + self.path, + // It's not great to catch errors here, since we can't give a very good path, + // but it's better than ICEing. + Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => { + InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait } + }, + ); } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 0e824f3f592d4..84557b8e2d600 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -88,22 +88,22 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { // Special treatment for special types, where the (static) layout is not sufficient. match *ty.kind() { // If it is a trait object, switch to the real type that was used to create it. - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { // Dyn types. This is unsized, and the actual dynamic type of the data is given by the // vtable stored in the place metadata. // unsized values are never immediate, so we can assert_mem_place let op = v.to_op(self.ecx())?; let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.0; + let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0; trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type return self.visit_field(v, 0, &inner_mplace.into()); } - ty::Dynamic(_, _, ty::DynStar) => { + ty::Dynamic(data, _, ty::DynStar) => { // DynStar types. Very different from a dyn type (but strangely part of the // same variant in `TyKind`): These are pairs where the 2nd component is the // vtable, and the first component is the data (which must be ptr-sized). - let data = self.ecx().unpack_dyn_star(v)?.0; + let data = self.ecx().unpack_dyn_star(v, data)?.0; return self.visit_field(v, 0, &data); } // Slices do not need special handling here: they have `Array` field diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 50420aaec045b..d27d42737cd6c 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -11,7 +11,6 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] -#![feature(generic_nonzero)] #![feature(let_chains)] #![feature(slice_ptr_get)] #![feature(strict_provenance)] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index a506d10c1d089..f9786acfc6c26 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -414,7 +414,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shared => { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) } - BorrowKind::Fake => { + BorrowKind::Fake(_) => { PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) } BorrowKind::Mut { .. } => { @@ -487,7 +487,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place) + Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place) | Rvalue::AddressOf(Mutability::Not, place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( self.ccx, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 2c835f6750f75..5ae3ffaaec2f2 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -105,7 +105,7 @@ where fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { match kind { mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Fake => { + mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) => { self.shared_borrow_allows_mutation(place) } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index bf5592c828f1b..837c02a5b769b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -965,7 +965,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } }, - Rvalue::Ref(_, BorrowKind::Fake, _) => { + Rvalue::Ref(_, BorrowKind::Fake(_), _) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b82a9a909e6d0..cf54e700e2b98 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -20,12 +20,12 @@ #![feature(cfg_match)] #![feature(core_intrinsics)] #![feature(extend_one)] -#![feature(generic_nonzero)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] #![feature(lazy_cell)] #![feature(lint_reasons)] #![feature(macro_metavar_expr)] +#![feature(map_try_insert)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] #![feature(negative_impls)] @@ -42,8 +42,6 @@ #[macro_use] extern crate tracing; -#[macro_use] -extern crate rustc_macros; use std::fmt; @@ -147,9 +145,9 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Printer { f } } -// See comments in compiler/rustc_middle/src/tests.rs +// See comment in compiler/rustc_middle/src/tests.rs and issue #27438. #[doc(hidden)] -pub fn __noop_fix_for_27438() {} +pub fn __noop_fix_for_windows_dllimport_issue() {} #[macro_export] macro_rules! external_bitflags_debug { diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 1436628139fde..21d7c91ec4826 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,4 +1,5 @@ use crate::stable_hasher::{HashStable, StableHasher, StableOrd}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; use std::borrow::Borrow; use std::fmt::Debug; use std::mem; diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 1cfc9fecd47d7..38629ea9801d9 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -6,9 +6,9 @@ //! compiled from distinct sources. use crate::fingerprint::Fingerprint; -use std::fmt; - use crate::stable_hasher; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)] pub struct Svh { diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index eab6d8168ca8e..ecb85db33f70d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -46,6 +46,7 @@ use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; mod lock; +#[doc(no_inline)] pub use lock::{Lock, LockGuard, Mode}; mod worker_local; @@ -199,10 +200,15 @@ cfg_match! { pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; + #[doc(no_inline)] pub use std::cell::Ref as ReadGuard; + #[doc(no_inline)] pub use std::cell::Ref as MappedReadGuard; + #[doc(no_inline)] pub use std::cell::RefMut as WriteGuard; + #[doc(no_inline)] pub use std::cell::RefMut as MappedWriteGuard; + #[doc(no_inline)] pub use std::cell::RefMut as MappedLockGuard; pub use std::cell::OnceCell as OnceLock; diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index a99e2062039bf..1ccd22a56c959 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -3,6 +3,8 @@ //! as required by the query system. use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use std::collections::hash_map::OccupiedError; use std::{ borrow::{Borrow, BorrowMut}, collections::hash_map::Entry, @@ -468,6 +470,11 @@ impl UnordMap { self.inner.insert(k, v) } + #[inline] + pub fn try_insert(&mut self, k: K, v: V) -> Result<&mut V, OccupiedError<'_, K, V>> { + self.inner.try_insert(k, v) + } + #[inline] pub fn contains_key(&self, k: &Q) -> bool where diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b3cba4dbfc20e..b2d38a00f0b5f 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -14,9 +14,6 @@ #![feature(panic_update_hook)] #![feature(result_flattening)] -#[macro_use] -extern crate tracing; - use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_const_eval::CTRL_C_RECEIVED; @@ -46,7 +43,6 @@ use rustc_span::symbol::sym; use rustc_span::FileName; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTriple}; - use std::cmp::max; use std::collections::BTreeMap; use std::env; @@ -62,6 +58,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; use time::OffsetDateTime; +use tracing::trace; #[allow(unused_macros)] macro do_not_use_print($($t:tt)*) { @@ -971,7 +968,7 @@ Available lint options: let lint_store = unerased_lint_store(sess); let (loaded, builtin): (Vec<_>, _) = - lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_loaded); + lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_externally_loaded); let loaded = sort_lints(sess, loaded); let builtin = sort_lints(sess, builtin); diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 40f6f76499371..fe426b8111cc3 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -13,9 +13,9 @@ use rustc_session::Session; use rustc_smir::rustc_internal::pretty::write_smir_pretty; use rustc_span::symbol::Ident; use rustc_span::FileName; - use std::cell::Cell; use std::fmt::Write; +use tracing::debug; pub use self::PpMode::*; pub use self::PpSourceMode::*; diff --git a/compiler/rustc_error_codes/src/error_codes/E0522.md b/compiler/rustc_error_codes/src/error_codes/E0522.md index 83272314a8708..b0dd5a775ac14 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0522.md +++ b/compiler/rustc_error_codes/src/error_codes/E0522.md @@ -6,7 +6,7 @@ Erroneous code example: #![feature(lang_items)] #[lang = "cookie"] -fn cookie() -> ! { // error: definition of an unknown language item: `cookie` +fn cookie() -> ! { // error: definition of an unknown lang item: `cookie` loop {} } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0626.md b/compiler/rustc_error_codes/src/error_codes/E0626.md index e2534415d8307..28d543350ffd8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0626.md +++ b/compiler/rustc_error_codes/src/error_codes/E0626.md @@ -4,10 +4,10 @@ yield point. Erroneous code example: ```compile_fail,E0626 -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let a = &String::new(); // <-- This borrow... yield (); // ...is still in scope here, when the yield occurs. println!("{}", a); @@ -23,10 +23,10 @@ resolve the previous example by removing the borrow and just storing the integer by value: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let a = 3; yield (); println!("{}", a); @@ -41,10 +41,10 @@ in those cases, something like the `Rc` or `Arc` types may be useful. This error also frequently arises with iteration: ```compile_fail,E0626 -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; for &x in &v { // <-- borrow of `v` is still in scope... yield x; // ...when this yield occurs. @@ -57,10 +57,10 @@ Such cases can sometimes be resolved by iterating "by value" (or using `into_iter()`) to avoid borrowing: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; for x in v { // <-- Take ownership of the values instead! yield x; // <-- Now yield is OK. @@ -72,10 +72,10 @@ Pin::new(&mut b).resume(()); If taking ownership is not an option, using indices can work too: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; let len = v.len(); // (*) for i in 0..len { diff --git a/compiler/rustc_error_codes/src/error_codes/E0627.md b/compiler/rustc_error_codes/src/error_codes/E0627.md index 5d366f78fc575..da2e2d355a160 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0627.md +++ b/compiler/rustc_error_codes/src/error_codes/E0627.md @@ -3,7 +3,7 @@ A yield expression was used outside of the coroutine literal. Erroneous code example: ```compile_fail,E0627 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn fake_coroutine() -> &'static str { yield 1; @@ -19,10 +19,10 @@ The error occurs because keyword `yield` can only be used inside the coroutine literal. This can be fixed by constructing the coroutine correctly. ``` -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0628.md b/compiler/rustc_error_codes/src/error_codes/E0628.md index ce19bcd56cc78..d0d387cf6c7ef 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0628.md +++ b/compiler/rustc_error_codes/src/error_codes/E0628.md @@ -3,10 +3,10 @@ More than one parameter was used for a coroutine. Erroneous code example: ```compile_fail,E0628 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let coroutine = |a: i32, b: i32| { + let coroutine = #[coroutine] |a: i32, b: i32| { // error: too many parameters for a coroutine // Allowed only 0 or 1 parameter yield a; @@ -20,10 +20,10 @@ at most 1 parameter for the coroutine. For example, we might resolve the previous example by passing only one parameter. ``` -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let coroutine = |a: i32| { + let coroutine = #[coroutine] |a: i32| { yield a; }; } diff --git a/compiler/rustc_error_codes/src/error_codes/E0637.md b/compiler/rustc_error_codes/src/error_codes/E0637.md index 62d5565df2798..9c2a53f51cf29 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0637.md +++ b/compiler/rustc_error_codes/src/error_codes/E0637.md @@ -1,5 +1,5 @@ `'_` lifetime name or `&T` without an explicit lifetime name has been used -on illegal place. +in an illegal place. Erroneous code example: @@ -13,7 +13,14 @@ fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { } } -fn and_without_explicit_lifetime() +fn without_explicit_lifetime() +where + T: Iterator, + //^ `&` without an explicit lifetime name +{ +} + +fn without_hrtb() where T: Into<&u32>, //^ `&` without an explicit lifetime name @@ -40,9 +47,15 @@ fn underscore_lifetime<'a>(str1: &'a str, str2: &'a str) -> &'a str { } } -fn and_without_explicit_lifetime<'foo, T>() +fn without_explicit_lifetime<'a, T>() +where + T: Iterator, +{ +} + +fn without_hrtb() where - T: Into<&'foo u32>, + T: for<'foo> Into<&'foo u32>, { } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0727.md b/compiler/rustc_error_codes/src/error_codes/E0727.md index fde35885c9208..7754186508f11 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0727.md +++ b/compiler/rustc_error_codes/src/error_codes/E0727.md @@ -3,10 +3,10 @@ A `yield` clause was used in an `async` context. Erroneous code example: ```compile_fail,E0727,edition2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let coroutine = || { + let coroutine = #[coroutine] || { async { yield; } @@ -20,10 +20,10 @@ which is not yet supported. To fix this error, you have to move `yield` out of the `async` block: ```edition2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let coroutine = || { + let coroutine = #[coroutine] || { yield; }; } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a17e0da47a5cf..1610135a0efad 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,6 +7,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; +use rustc_macros::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -17,6 +18,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic; use std::thread::panicking; +use tracing::debug; /// Error type for `DiagInner`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `DiagInner`. @@ -177,7 +179,7 @@ where { /// Add a subdiagnostic to an existing diagnostic. fn add_to_diag(self, diag: &mut Diag<'_, G>) { - self.add_to_diag_with(diag, |_, m| m); + self.add_to_diag_with(diag, &|_, m| m); } /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used @@ -185,7 +187,7 @@ where fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ); } @@ -1197,7 +1199,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { dcx: &crate::DiagCtxt, subdiagnostic: impl Subdiagnostic, ) -> &mut Self { - subdiagnostic.add_to_diag_with(self, |diag, msg| { + subdiagnostic.add_to_diag_with(self, &|diag, msg| { let args = diag.args.iter(); let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); dcx.eagerly_translate(msg, args) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 6c0551848d688..b3a1e29f8e2cb 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -7,6 +7,7 @@ use crate::{ use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; +use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::Span; @@ -227,6 +228,36 @@ impl IntoDiagArg for rustc_lint_defs::Level { } } +impl IntoDiagArg for hir::def::Res { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::Borrowed(self.descr())) + } +} + +impl IntoDiagArg for DiagLocation { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::from(self.to_string())) + } +} + +impl IntoDiagArg for Backtrace { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::from(self.to_string())) + } +} + +impl IntoDiagArg for Level { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::from(self.to_string())) + } +} + +impl IntoDiagArg for type_ir::ClosureKind { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(self.as_str().into()) + } +} + #[derive(Clone)] pub struct DiagSymbolList(Vec); @@ -244,12 +275,6 @@ impl IntoDiagArg for DiagSymbolList { } } -impl IntoDiagArg for hir::def::Res { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(self.descr())) - } -} - impl Diagnostic<'_, G> for TargetDataLayoutErrors<'_> { fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { match self { @@ -302,7 +327,7 @@ impl Subdiagnostic for SingleLabelManySpans { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _: F, + _: &F, ) { diag.span_labels(self.spans, self.label); } @@ -316,24 +341,6 @@ pub struct ExpectedLifetimeParameter { pub count: usize, } -impl IntoDiagArg for DiagLocation { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - -impl IntoDiagArg for Backtrace { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - -impl IntoDiagArg for Level { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - #[derive(Subdiagnostic)] #[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")] pub struct IndicateAnonymousLifetime { @@ -343,8 +350,10 @@ pub struct IndicateAnonymousLifetime { pub suggestion: String, } -impl IntoDiagArg for type_ir::ClosureKind { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(self.as_str().into()) - } +#[derive(Subdiagnostic)] +pub struct ElidedLifetimeInPathSubdiag { + #[subdiagnostic] + pub expected: ExpectedLifetimeParameter, + #[subdiagnostic] + pub indicate: Option, } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 6ce3fa3535dc9..5d4d2555100ed 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -35,6 +35,7 @@ use std::iter; use std::path::Path; use termcolor::{Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream}; use termcolor::{Color, WriteColor}; +use tracing::{debug, instrument, trace, warn}; /// Default column width, used in tests and when terminal dimensions cannot be determined. const DEFAULT_COLUMN_WIDTH: usize = 140; @@ -984,7 +985,7 @@ impl HumanEmitter { // 4 | } // | for pos in 0..=line_len { - draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); + draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); } // Write the horizontal lines for multiline annotations @@ -2019,7 +2020,7 @@ impl HumanEmitter { let offset: isize = offsets .iter() .filter_map( - |(start, v)| if span_start_pos <= *start { None } else { Some(v) }, + |(start, v)| if span_start_pos < *start { None } else { Some(v) }, ) .sum(); let underline_start = (span_start_pos + start) as isize + offset; @@ -2028,7 +2029,7 @@ impl HumanEmitter { let padding: usize = max_line_num_len + 3; for p in underline_start..underline_end { if let DisplaySuggestion::Underline = show_code_change { - // If this is a replacement, underline with `^`, if this is an addition + // If this is a replacement, underline with `~`, if this is an addition // underline with `+`. buffer.putc( row_num, @@ -2260,13 +2261,23 @@ impl HumanEmitter { buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); } [] => { - draw_col_separator(buffer, *row_num, max_line_num_len + 1); + draw_col_separator_no_space(buffer, *row_num, max_line_num_len + 1); } _ => { buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition); } } - buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + // LL | line_to_add + // ++^^^ + // | | + // | magic `3` + // `max_line_num_len` + buffer.puts( + *row_num, + max_line_num_len + 3, + &normalize_whitespace(line_to_add), + Style::NoStyle, + ); } else if let DisplaySuggestion::Add = show_code_change { buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8d6b22a9fa988..3b884ff864ab1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,7 +15,6 @@ #![feature(box_patterns)] #![feature(error_reporter)] #![feature(extract_if)] -#![feature(generic_nonzero)] #![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] @@ -26,12 +25,6 @@ #![feature(yeet_expr)] // tidy-alphabetical-end -#[macro_use] -extern crate rustc_macros; - -#[macro_use] -extern crate tracing; - extern crate self as rustc_errors; pub use codes::*; @@ -41,8 +34,8 @@ pub use diagnostic::{ SubdiagMessageOp, Subdiagnostic, }; pub use diagnostic_impls::{ - DiagArgFromDisplay, DiagSymbolList, ExpectedLifetimeParameter, IndicateAnonymousLifetime, - SingleLabelManySpans, + DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, + IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; pub use rustc_error_messages::{ @@ -65,6 +58,7 @@ use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::AtomicRef; use rustc_lint_defs::LintExpectationId; +use rustc_macros::{Decodable, Encodable}; use rustc_span::source_map::SourceMap; use rustc_span::{Loc, Span, DUMMY_SP}; use std::backtrace::{Backtrace, BacktraceStatus}; @@ -77,6 +71,7 @@ use std::num::NonZero; use std::ops::DerefMut; use std::panic; use std::path::{Path, PathBuf}; +use tracing::debug; use Level::*; @@ -503,7 +498,7 @@ struct DiagCtxtInner { } /// A key denoting where from a diagnostic was stashed. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, @@ -780,7 +775,7 @@ impl DiagCtxt { // We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs` // can be used to create a backtrace at the stashing site insted of whenever the // diagnostic context is dropped and thus delayed bugs are emitted. - Error => Some(self.span_delayed_bug(span, "stashing {key:?}")), + Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))), DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag), ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow | Expect(_) => None, @@ -1912,27 +1907,24 @@ impl Level { } // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite. -pub fn add_elided_lifetime_in_path_suggestion( +pub fn elided_lifetime_in_path_suggestion( source_map: &SourceMap, - diag: &mut Diag<'_, G>, n: usize, path_span: Span, incl_angl_brckt: bool, insertion_span: Span, -) { - diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n }); - if !source_map.is_span_accessible(insertion_span) { - // Do not try to suggest anything if generated by a proc-macro. - return; - } - let anon_lts = vec!["'_"; n].join(", "); - let suggestion = - if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") }; - - diag.subdiagnostic( - diag.dcx, - IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }, - ); +) -> ElidedLifetimeInPathSubdiag { + let expected = ExpectedLifetimeParameter { span: path_span, count: n }; + // Do not try to suggest anything if generated by a proc-macro. + let indicate = source_map.is_span_accessible(insertion_span).then(|| { + let anon_lts = vec!["'_"; n].join(", "); + let suggestion = + if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") }; + + IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion } + }); + + ElidedLifetimeInPathSubdiag { expected, indicate } } pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index b55f78538852a..d6119fb41d225 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -1,6 +1,7 @@ // Code for annotating snippets. use crate::{Level, Loc}; +use rustc_macros::{Decodable, Encodable}; #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Line { diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index bf0026568ce23..445e9b4fd6e04 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -6,6 +6,7 @@ pub use rustc_error_messages::FluentArgs; use std::borrow::Cow; use std::env; use std::error::Report; +use tracing::{debug, trace}; /// Convert diagnostic arguments (a rustc internal type that exists to implement /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index fdd1a87cae809..b7aae2af9ef97 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -30,9 +30,6 @@ expand_duplicate_matcher_binding = duplicate matcher binding .label = duplicate binding .label2 = previous binding -expand_expected_comma_in_list = - expected token: `,` - expand_expected_paren_or_brace = expected `(` or `{"{"}`, found `{$token}` @@ -116,9 +113,6 @@ expand_must_repeat_once = expand_not_a_meta_item = not a meta item -expand_only_one_argument = - {$name} takes 1 argument - expand_only_one_word = must only be one word @@ -146,9 +140,6 @@ expand_remove_node_not_supported = expand_resolve_relative_path = cannot resolve relative path in non-file source `{$path}` -expand_takes_no_arguments = - {$name} takes no arguments - expand_trace_macro = trace_macro expand_unsupported_key_value = diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b25dd8fe67b78..6fe74edbd70a8 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -5,27 +5,26 @@ use crate::module::DirOwnership; use rustc_ast::attr::MarkedAttrs; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Nonterminal}; +use rustc_ast::token::Nonterminal; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{Applicability, Diag, DiagCtxt, ErrorGuaranteed, PResult}; +use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, RegisteredTools}; use rustc_parse::{parser, MACRO_ARGUMENTS}; use rustc_session::config::CollapseMacroDebuginfo; -use rustc_session::errors::report_lit_error; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, FileName, Span, DUMMY_SP}; +use rustc_span::{FileName, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::default::Default; use std::iter; @@ -789,55 +788,50 @@ impl SyntaxExtension { } } - fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo { - use crate::errors::CollapseMacroDebuginfoIllegal; - // #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)]) - // considered as `yes` - attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| { - let [NestedMetaItem::MetaItem(item)] = &l[..] else { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span }); - return CollapseMacroDebuginfo::Unspecified; - }; - if !item.is_word() { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); - CollapseMacroDebuginfo::Unspecified - } else { - match item.name_or_empty() { - sym::no => CollapseMacroDebuginfo::No, - sym::external => CollapseMacroDebuginfo::External, - sym::yes => CollapseMacroDebuginfo::Yes, - _ => { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); - CollapseMacroDebuginfo::Unspecified - } - } - } - }) + fn collapse_debuginfo_by_name(attr: &Attribute) -> Result { + let list = attr.meta_item_list(); + let Some([NestedMetaItem::MetaItem(item)]) = list.as_deref() else { + return Err(attr.span); + }; + if !item.is_word() { + return Err(item.span); + } + + match item.name_or_empty() { + sym::no => Ok(CollapseMacroDebuginfo::No), + sym::external => Ok(CollapseMacroDebuginfo::External), + sym::yes => Ok(CollapseMacroDebuginfo::Yes), + _ => Err(item.path.span), + } } /// if-ext - if macro from different crate (related to callsite code) /// | cmd \ attr | no | (unspecified) | external | yes | /// | no | no | no | no | no | - /// | (unspecified) | no | no | if-ext | yes | + /// | (unspecified) | no | if-ext | if-ext | yes | /// | external | no | if-ext | if-ext | yes | /// | yes | yes | yes | yes | yes | - fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool { - let mut collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) - .map(|v| Self::collapse_debuginfo_by_name(sess, v)) - .unwrap_or(CollapseMacroDebuginfo::Unspecified); - if collapse_debuginfo_attr == CollapseMacroDebuginfo::Unspecified - && attr::contains_name(attrs, sym::rustc_builtin_macro) - { - collapse_debuginfo_attr = CollapseMacroDebuginfo::Yes; - } - - let flag = sess.opts.unstable_opts.collapse_macro_debuginfo; - let attr = collapse_debuginfo_attr; - let ext = !is_local; + fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], ext: bool) -> bool { + let flag = sess.opts.cg.collapse_macro_debuginfo; + let attr = attr::find_by_name(attrs, sym::collapse_debuginfo) + .and_then(|attr| { + Self::collapse_debuginfo_by_name(attr) + .map_err(|span| { + sess.dcx().emit_err(errors::CollapseMacroDebuginfoIllegal { span }) + }) + .ok() + }) + .unwrap_or_else(|| { + if attr::contains_name(attrs, sym::rustc_builtin_macro) { + CollapseMacroDebuginfo::Yes + } else { + CollapseMacroDebuginfo::Unspecified + } + }); #[rustfmt::skip] let collapse_table = [ [false, false, false, false], - [false, false, ext, true], + [false, ext, ext, true], [false, ext, ext, true], [true, true, true, true], ]; @@ -864,7 +858,7 @@ impl SyntaxExtension { let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local); + let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local); tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) @@ -968,7 +962,12 @@ impl SyntaxExtension { /// Error type that denotes indeterminacy. pub struct Indeterminate; -pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option>, bool)>; +pub struct DeriveResolution { + pub path: ast::Path, + pub item: Annotatable, + pub exts: Option>, + pub is_const: bool, +} pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; @@ -1011,11 +1010,11 @@ pub trait ResolverExpand { &mut self, expn_id: LocalExpnId, force: bool, - derive_paths: &dyn Fn() -> DeriveResolutions, + derive_paths: &dyn Fn() -> Vec, ) -> Result<(), Indeterminate>; /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId` /// back from resolver. - fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option; + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option>; /// Path resolution logic for `#[cfg_accessible(path)]`. fn cfg_accessible( &mut self, @@ -1269,181 +1268,6 @@ pub fn resolve_path(sess: &Session, path: impl Into, span: Span) -> PRe } } -/// `Ok` represents successfully retrieving the string literal at the correct -/// position, e.g., `println("abc")`. -type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>; - -/// - `Ok` is returned when the conversion to a string literal is unsuccessful, -/// but another type of expression is obtained instead. -/// - `Err` is returned when the conversion process fails. -type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>; - -/// Extracts a string literal from the macro expanded version of `expr`, -/// returning a diagnostic error of `err_msg` if `expr` is not a string literal. -/// The returned bool indicates whether an applicable suggestion has already been -/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))` -/// indicates that an ast error was encountered. -// FIXME(Nilstrieb) Make this function setup translatable -#[allow(rustc::untranslatable_diagnostic)] -pub fn expr_to_spanned_string<'a>( - cx: &'a mut ExtCtxt<'_>, - expr: P, - err_msg: &'static str, -) -> ExpandResult, ()> { - if !cx.force_mode - && let ast::ExprKind::MacCall(m) = &expr.kind - && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() - { - return ExpandResult::Retry(()); - } - - // Perform eager expansion on the expression. - // We want to be able to handle e.g., `concat!("foo", "bar")`. - let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); - - ExpandResult::Ready(Err(match expr.kind { - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Str(s, style)) => { - return ExpandResult::Ready(Ok((s, style, expr.span))); - } - Ok(ast::LitKind::ByteStr(..)) => { - let mut err = cx.dcx().struct_span_err(expr.span, err_msg); - let span = expr.span.shrink_to_lo(); - err.span_suggestion( - span.with_hi(span.lo() + BytePos(1)), - "consider removing the leading `b`", - "", - Applicability::MaybeIncorrect, - ); - Ok((err, true)) - } - Ok(ast::LitKind::Err(guar)) => Err(guar), - Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)), - _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), - }, - ast::ExprKind::Err(guar) => Err(guar), - ast::ExprKind::Dummy => { - cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") - } - _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), - })) -} - -/// Extracts a string literal from the macro expanded version of `expr`, -/// emitting `err_msg` if `expr` is not a string literal. This does not stop -/// compilation on error, merely emits a non-fatal error and returns `Err`. -pub fn expr_to_string( - cx: &mut ExtCtxt<'_>, - expr: P, - err_msg: &'static str, -) -> ExpandResult, ()> { - expr_to_spanned_string(cx, expr, err_msg).map(|res| { - res.map_err(|err| match err { - Ok((err, _)) => err.emit(), - Err(guar) => guar, - }) - .map(|(symbol, style, _)| (symbol, style)) - }) -} - -/// Non-fatally assert that `tts` is empty. Note that this function -/// returns even when `tts` is non-empty, macros that *need* to stop -/// compilation should call `cx.diagnostic().abort_if_errors()` -/// (this should be done as rarely as possible). -pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { - if !tts.is_empty() { - cx.dcx().emit_err(errors::TakesNoArguments { span, name }); - } -} - -/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. -pub fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> { - let guar = match p.parse_expr() { - Ok(expr) => return Ok(expr), - Err(err) => err.emit(), - }; - while p.token != token::Eof { - p.bump(); - } - Err(guar) -} - -/// Interpreting `tts` as a comma-separated sequence of expressions, -/// expect exactly one string literal, or emit an error and return `Err`. -pub fn get_single_str_from_tts( - cx: &mut ExtCtxt<'_>, - span: Span, - tts: TokenStream, - name: &str, -) -> ExpandResult, ()> { - get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s)) -} - -pub fn get_single_str_spanned_from_tts( - cx: &mut ExtCtxt<'_>, - span: Span, - tts: TokenStream, - name: &str, -) -> ExpandResult, ()> { - let mut p = cx.new_parser_from_tts(tts); - if p.token == token::Eof { - let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); - return ExpandResult::Ready(Err(guar)); - } - let ret = match parse_expr(&mut p) { - Ok(ret) => ret, - Err(guar) => return ExpandResult::Ready(Err(guar)), - }; - let _ = p.eat(&token::Comma); - - if p.token != token::Eof { - cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); - } - expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| { - res.map_err(|err| match err { - Ok((err, _)) => err.emit(), - Err(guar) => guar, - }) - .map(|(symbol, _style, span)| (symbol, span)) - }) -} - -/// Extracts comma-separated expressions from `tts`. -/// On error, emit it, and return `Err`. -pub fn get_exprs_from_tts( - cx: &mut ExtCtxt<'_>, - tts: TokenStream, -) -> ExpandResult>, ErrorGuaranteed>, ()> { - let mut p = cx.new_parser_from_tts(tts); - let mut es = Vec::new(); - while p.token != token::Eof { - let expr = match parse_expr(&mut p) { - Ok(expr) => expr, - Err(guar) => return ExpandResult::Ready(Err(guar)), - }; - if !cx.force_mode - && let ast::ExprKind::MacCall(m) = &expr.kind - && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() - { - return ExpandResult::Retry(()); - } - - // Perform eager expansion on the expression. - // We want to be able to handle e.g., `concat!("foo", "bar")`. - let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); - - es.push(expr); - if p.eat(&token::Comma) { - continue; - } - if p.token != token::Eof { - let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span }); - return ExpandResult::Ready(Err(guar)); - } - } - ExpandResult::Ready(Ok(es)) -} - pub fn parse_macro_name_and_helper_attrs( dcx: &rustc_errors::DiagCtxt, attr: &Attribute, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index c95d7cdeb73ab..b554a5ccd1961 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -20,6 +20,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use thin_vec::ThinVec; +use tracing::instrument; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 21ce5e1d81e6e..b0563bfdea749 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -1,6 +1,6 @@ use rustc_ast::ast; use rustc_errors::codes::*; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::Limit; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; use rustc_span::{Span, Symbol}; @@ -152,29 +152,6 @@ pub(crate) struct HelperAttributeNameInvalid { pub name: Ident, } -#[derive(Diagnostic)] -#[diag(expand_expected_comma_in_list)] -pub(crate) struct ExpectedCommaInList { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(expand_only_one_argument)] -pub(crate) struct OnlyOneArgument<'a> { - #[primary_span] - pub span: Span, - pub name: &'a str, -} - -#[derive(Diagnostic)] -#[diag(expand_takes_no_arguments)] -pub(crate) struct TakesNoArguments<'a> { - #[primary_span] - pub span: Span, - pub name: &'a str, -} - #[derive(Diagnostic)] #[diag(expand_feature_removed, code = E0557)] pub(crate) struct FeatureRemoved<'a> { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6029caa965c0b..503c9170cab53 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -482,7 +482,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derive_invocations.reserve(derives.len()); derives .into_iter() - .map(|(path, item, _exts, is_const)| { + .map(|DeriveResolution { path, item, exts: _, is_const }| { // FIXME: Consider using the derive resolutions (`_exts`) // instead of enqueuing the derives to be resolved again later. let expn_id = LocalExpnId::fresh_empty(); @@ -1218,7 +1218,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> fragment.make_trait_items() } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_assoc_item(self.wrapped, visitor) + noop_flat_map_item(self.wrapped, visitor) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1243,7 +1243,7 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> fragment.make_impl_items() } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_assoc_item(self.wrapped, visitor) + noop_flat_map_item(self.wrapped, visitor) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1266,7 +1266,7 @@ impl InvocationCollectorNode for P { fragment.make_foreign_items() } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_foreign_item(self, visitor) + noop_flat_map_item(self, visitor) } fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index c9a3aeedd0209..3c9d2e8706835 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(array_windows)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(associated_type_defaults)] #![feature(if_let_guard)] #![feature(let_chains)] @@ -16,12 +15,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_macros; - -#[macro_use] -extern crate tracing; - extern crate proc_macro as pm; mod placeholders; diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index ca4a1f327adc8..bd6a9b7cb07da 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -14,6 +14,7 @@ pub(crate) mod transcribe; use metavar_expr::MetaVarExpr; use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan}; +use rustc_macros::{Decodable, Encodable}; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 15193298ccaa2..5d6c3e8aa3a4a 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -8,11 +8,13 @@ use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagCtxt, DiagMessage}; +use rustc_macros::Subdiagnostic; use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span}; use std::borrow::Cow; +use tracing::debug; use super::macro_rules::{parser_from_cx, NoopTracker}; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 7099f1b0d3521..df2643ad1ddea 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -29,6 +29,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; +use tracing::{debug, instrument, trace, trace_span}; use std::borrow::Cow; use std::collections::hash_map::Entry; diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 81e1de5b09544..8239cfd46cbfe 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -3,6 +3,7 @@ use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree}; use rustc_ast::{LitIntType, LitKind}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; +use rustc_macros::{Decodable, Encodable}; use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 2c4187031cacf..581d71875bd07 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -271,14 +271,14 @@ impl MutVisitor for PlaceholderExpander { fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(), - _ => noop_flat_map_assoc_item(item, self), + _ => noop_flat_map_item(item, self), } } fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(), - _ => noop_flat_map_assoc_item(item, self), + _ => noop_flat_map_item(item, self), } } @@ -288,7 +288,7 @@ impl MutVisitor for PlaceholderExpander { ) -> SmallVec<[P; 1]> { match item.kind { ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(), - _ => noop_flat_map_foreign_item(item, self), + _ => noop_flat_map_item(item, self), } } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 1eee11604cef8..943cc63285787 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -60,7 +60,7 @@ declare_features! ( /// Allows the definition of associated constants in `trait` or `impl` blocks. (accepted, associated_consts, "1.20.0", Some(29646)), /// Allows the user of associated type bounds. - (accepted, associated_type_bounds, "CURRENT_RUSTC_VERSION", Some(52662)), + (accepted, associated_type_bounds, "1.79.0", Some(52662)), /// Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None), /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. @@ -98,6 +98,8 @@ declare_features! ( (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)), /// Allows using the CMPXCHG16B target feature. (accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839)), + /// Allows use of the `#[collapse_debuginfo]` attribute. + (accepted, collapse_debuginfo, "1.79.0", Some(100758)), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872)), /// Allows `impl Trait` in function return types. @@ -206,11 +208,13 @@ declare_features! ( /// Allows referencing `Self` and projections in impl-trait. (accepted, impl_trait_projections, "1.74.0", Some(103532)), /// Allows using imported `main` function - (accepted, imported_main, "CURRENT_RUSTC_VERSION", Some(28937)), + (accepted, imported_main, "1.79.0", Some(28937)), /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237)), /// Allows inferring outlives requirements (RFC 2093). (accepted, infer_outlives_requirements, "1.30.0", Some(44493)), + /// Allow anonymous constants from an inline `const` block + (accepted, inline_const, "1.79.0", Some(76001)), /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). (accepted, irrefutable_let_patterns, "1.33.0", Some(44495)), /// Allows `#[instruction_set(_)]` attribute. @@ -356,7 +360,7 @@ declare_features! ( /// Allows macros to appear in the type position. (accepted, type_macros, "1.13.0", Some(27245)), /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). - (accepted, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054)), + (accepted, type_privacy_lints, "1.79.0", Some(48054)), /// Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912)), /// Allows `use path as _;` and `extern crate c as _;`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 4f62323231a73..9d3aac66c4103 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -450,6 +450,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk, EncodeCrossCrate::No ), + ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing, + EncodeCrossCrate::Yes + ), // ========================================================================== // Unstable attributes: @@ -516,12 +519,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, experimental!(deprecated_safe), ), - // `#[collapse_debuginfo]` - gated!( - collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing, - EncodeCrossCrate::No, experimental!(collapse_debuginfo) - ), - // RFC 2397 gated!( do_not_recommend, Normal, template!(Word), WarnFollowing, @@ -534,6 +531,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, experimental!(cfi_encoding) ), + // `#[coroutine]` attribute to be applied to closures to make them coroutines instead + gated!( + coroutine, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, coroutines, experimental!(coroutines) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -798,7 +801,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== gated!( lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items, - "language items are subject to change", + "lang items are subject to change", ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index cb28bb4e8e4ff..36ef8fe7816fe 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -12,7 +12,6 @@ //! symbol to the `accepted` or `removed` modules respectively. #![allow(internal_features)] -#![feature(generic_nonzero)] #![feature(rustdoc_internals)] #![doc(rust_logo)] #![feature(lazy_cell)] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9641d336c3f3c..e7d7a9f380b19 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -216,7 +216,7 @@ declare_features! ( /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity, "1.78.0", None), /// Allows using pattern types. - (internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(123646)), + (internal, pattern_types, "1.79.0", Some(123646)), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -384,7 +384,7 @@ declare_features! ( /// Allows `cfg(target_thread_local)`. (unstable, cfg_target_thread_local, "1.7.0", Some(29594)), /// Allows the use of `#[cfg(ub_checks)` to check if UB checks are enabled. - (unstable, cfg_ub_checks, "CURRENT_RUSTC_VERSION", Some(123499)), + (unstable, cfg_ub_checks, "1.79.0", Some(123499)), /// Allow conditional compilation depending on rust version (unstable, cfg_version, "1.45.0", Some(64796)), /// Allows to use the `#[cfi_encoding = ""]` attribute. @@ -395,8 +395,6 @@ declare_features! ( (unstable, closure_track_caller, "1.57.0", Some(87417)), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), - /// Allows use of the `#[collapse_debuginfo]` attribute. - (unstable, collapse_debuginfo, "1.65.0", Some(100758)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), /// Allows `const || {}` closures in const contexts. @@ -441,7 +439,7 @@ declare_features! ( /// Allows having using `suggestion` in the `#[deprecated]` attribute. (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. - (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)), + (incomplete, deref_patterns, "1.79.0", Some(87121)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. @@ -501,8 +499,6 @@ declare_features! ( (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), - /// Allow anonymous constants from an inline `const` block - (unstable, inline_const, "1.49.0", Some(76001)), /// Allow anonymous constants from an inline `const` block in pattern position (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links @@ -534,9 +530,9 @@ declare_features! ( /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Make `mut` not reset the binding mode on edition >= 2024. - (incomplete, mut_preserve_binding_mode_2024, "CURRENT_RUSTC_VERSION", Some(123076)), + (incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)), /// Allows `mut ref` and `mut ref mut` identifier patterns. - (incomplete, mut_ref, "CURRENT_RUSTC_VERSION", Some(123076)), + (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. (unstable, naked_functions, "1.9.0", Some(90957)), /// Allows specifying the as-needed link modifier @@ -568,17 +564,17 @@ declare_features! ( /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` - (unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)), + (unstable, postfix_match, "1.79.0", Some(121618)), /// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args. - (incomplete, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)), + (incomplete, precise_capturing, "1.79.0", Some(123432)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. - (incomplete, ref_pat_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)), + (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. - (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)), + (incomplete, ref_pat_everywhere, "1.79.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 3359fef8c1c46..d376c24cb589c 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(absolute_path)] - use std::ffi::CString; use std::fs; use std::io; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 37d9b2ffd6ab8..649a08b6972fb 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_ast::NodeId; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_data_structures::unord::UnordMap; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::kw; diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index cd5da279a2621..35833e258d558 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -7,14 +7,14 @@ pub use crate::def_id::DefPathHash; use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::def_path_hash_map::DefPathHashMap; - use rustc_data_structures::stable_hasher::{Hash64, StableHasher}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; +use rustc_macros::{Decodable, Encodable}; use rustc_span::symbol::{kw, sym, Symbol}; - use std::fmt::{self, Write}; use std::hash::Hash; +use tracing::{debug, instrument}; /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e4f8d77dbc2e5..fc8f7466694c7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3,7 +3,6 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::FnKind; use crate::LangItem; - use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy}; @@ -13,7 +12,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_index::IndexVec; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -21,9 +20,9 @@ use rustc_span::ErrorGuaranteed; use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; use rustc_target::spec::abi::Abi; - use smallvec::SmallVec; use std::fmt; +use tracing::debug; #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { @@ -644,13 +643,49 @@ impl<'hir> Generics<'hir> { }) } - pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option { + /// Returns a suggestable empty span right after the "final" bound of the generic parameter. + /// + /// If that bound needs to be wrapped in parentheses to avoid ambiguity with + /// subsequent bounds, it also returns an empty span for an open parenthesis + /// as the second component. + /// + /// E.g., adding `+ 'static` after `Fn() -> dyn Future` or + /// `Fn() -> &'static dyn Debug` requires parentheses: + /// `Fn() -> (dyn Future) + 'static` and + /// `Fn() -> &'static (dyn Debug) + 'static`, respectively. + pub fn bounds_span_for_suggestions( + &self, + param_def_id: LocalDefId, + ) -> Option<(Span, Option)> { self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map( |bound| { - // We include bounds that come from a `#[derive(_)]` but point at the user's code, - // as we use this method to get a span appropriate for suggestions. - let bs = bound.span(); - bs.can_be_used_for_suggestions().then(|| bs.shrink_to_hi()) + let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref() + && let [.., segment] = trait_ref.path.segments + && segment.args().parenthesized == GenericArgsParentheses::ParenSugar + && let [binding] = segment.args().bindings + && let TypeBindingKind::Equality { term: Term::Ty(ret_ty) } = binding.kind + && let ret_ty = ret_ty.peel_refs() + && let TyKind::TraitObject( + _, + _, + TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar, + ) = ret_ty.kind + && ret_ty.span.can_be_used_for_suggestions() + { + Some(ret_ty.span) + } else { + None + }; + + span_for_parentheses.map_or_else( + || { + // We include bounds that come from a `#[derive(_)]` but point at the user's code, + // as we use this method to get a span appropriate for suggestions. + let bs = bound.span(); + bs.can_be_used_for_suggestions().then(|| (bs.shrink_to_hi(), None)) + }, + |span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))), + ) }, ) } @@ -1775,6 +1810,44 @@ impl Expr<'_> { } } + /// Whether this and the `other` expression are the same for purposes of an indexing operation. + /// + /// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is + /// borrowed multiple times with `i`. + pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool { + match (self.kind, other.kind) { + (ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node, + ( + ExprKind::Path(QPath::LangItem(item1, _)), + ExprKind::Path(QPath::LangItem(item2, _)), + ) => item1 == item2, + ( + ExprKind::Path(QPath::Resolved(None, path1)), + ExprKind::Path(QPath::Resolved(None, path2)), + ) => path1.res == path2.res, + ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None), + ) + | ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None), + ) + | ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None), + ) => val1.expr.equivalent_for_indexing(val2.expr), + ( + ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None), + ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None), + ) => { + val1.expr.equivalent_for_indexing(val2.expr) + && val3.expr.equivalent_for_indexing(val4.expr) + } + _ => false, + } + } + pub fn method_ident(&self) -> Option { match self.kind { ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), @@ -3789,6 +3862,7 @@ impl<'hir> Node<'hir> { #[cfg(target_pointer_width = "64")] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(Block<'_>, 48); static_assert_size!(Body<'_>, 24); diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 0341a482fa8c1..ac48746950709 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -1,5 +1,6 @@ use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{def_id::DefPathHash, HashStableContext}; use std::fmt::{self, Debug}; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 2a796ca5465c9..e870a04127ada 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -1,4 +1,4 @@ -//! Defines language items. +//! Defines lang items. //! //! Language items are items that represent concepts intrinsic to the language //! itself. Examples are: @@ -12,11 +12,11 @@ use crate::{MethodKind, Target}; use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -/// All of the language items, defined or not. +/// All of the lang items, defined or not. /// Defined lang items can come from the current crate or its dependencies. #[derive(HashStable_Generic, Debug)] pub struct LanguageItems { @@ -56,8 +56,8 @@ macro_rules! language_item_table { $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* ) => { - enum_from_u32! { - /// A representation of all the valid language items in Rust. + rustc_data_structures::enum_from_u32! { + /// A representation of all the valid lang items in Rust. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum LangItem { $( @@ -162,10 +162,22 @@ language_item_table! { Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None; Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None; + AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::Exact(0); + AsyncDestruct, sym::async_destruct, async_destruct_trait, Target::Trait, GenericRequirement::Exact(0); + AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); + SurfaceAsyncDropInPlace, sym::surface_async_drop_in_place, surface_async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropSurfaceDropInPlace, sym::async_drop_surface_drop_in_place, async_drop_surface_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropSlice, sym::async_drop_slice, async_drop_slice_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropChain, sym::async_drop_chain, async_drop_chain_fn, Target::Fn, GenericRequirement::Exact(2); + AsyncDropNoop, sym::async_drop_noop, async_drop_noop_fn, Target::Fn, GenericRequirement::Exact(0); + AsyncDropFuse, sym::async_drop_fuse, async_drop_fuse_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropDefer, sym::async_drop_defer, async_drop_defer_fn, Target::Fn, GenericRequirement::Exact(1); + AsyncDropEither, sym::async_drop_either, async_drop_either_fn, Target::Fn, GenericRequirement::Exact(3); + CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); - // language items relating to transmutability + // lang items relating to transmutability TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(2); @@ -281,6 +293,7 @@ language_item_table! { ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); + FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); @@ -291,7 +304,7 @@ language_item_table! { OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1); GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None; - // Experimental language item for Miri + // Experimental lang item for Miri PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1); PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c5c4075c6baa6..600a0dce03b94 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -10,15 +10,6 @@ #![feature(variant_count)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_macros; - -#[macro_use] -extern crate tracing; - -#[macro_use] -extern crate rustc_data_structures; - extern crate self as rustc_hir; mod arena; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 06b5ee299b855..3edea0191faf1 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -201,6 +201,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}` + .note = type of `self` must be `Self` or a type that dereferences to it + +hir_analysis_invalid_receiver_ty_help = + consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + hir_analysis_invalid_union_field = field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` @@ -486,13 +492,13 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de hir_analysis_ty_of_assoc_const_binding_note = `{$assoc_const}` has type `{$ty}` -hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) - .label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) +hir_analysis_ty_param_first_local = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`) + .label = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`) .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type .case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last -hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`) - .label = type parameter `{$param_ty}` must be used as the type parameter for some local type +hir_analysis_ty_param_some = type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`) + .label = type parameter `{$param}` must be used as the type parameter for some local type .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local .only_note = only traits defined in the current crate can be implemented for a type parameter diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index d3f51195dfb29..aafb5c1c0b4bc 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -43,16 +43,6 @@ impl<'tcx> Bounds<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, - ) { - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - } - - fn push_trait_bound_inner( - &mut self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - span: Span, - polarity: ty::PredicatePolarity, ) { let clause = ( trait_ref diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a43a67d50d810..32e1b19eaaeb9 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -10,11 +10,10 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::Node; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::{Obligation, TraitEngineExt as _}; +use rustc_infer::traits::Obligation; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -24,10 +23,10 @@ use rustc_middle::ty::{ }; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_target::abi::FieldIdx; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _}; use rustc_type_ir::fold::TypeFoldable; use std::cell::LazyCell; @@ -1715,55 +1714,31 @@ fn opaque_type_cycle_error( err.emit() } -// FIXME(@lcnr): This should not be computed per coroutine, but instead once for -// each typeck root. pub(super) fn check_coroutine_obligations( tcx: TyCtxt<'_>, def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - debug_assert!(tcx.is_coroutine(def_id.to_def_id())); + debug_assert!(!tcx.is_typeck_child(def_id.to_def_id())); - let typeck = tcx.typeck(def_id); - let param_env = tcx.param_env(typeck.hir_owner.def_id); + let typeck_results = tcx.typeck(def_id); + let param_env = tcx.param_env(def_id); - let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id]; - debug!(?coroutine_interior_predicates); + debug!(?typeck_results.coroutine_stalled_predicates); let infcx = tcx .infer_ctxt() // typeck writeback gives us predicates with their regions erased. // As borrowck already has checked lifetimes, we do not need to do it again. .ignoring_regions() - // Bind opaque types to type checking root, as they should have been checked by borrowck, - // but may show up in some cases, like when (root) obligations are stalled in the new solver. - .with_opaque_type_inference(typeck.hir_owner.def_id) + .with_opaque_type_inference(def_id) .build(); - let mut fulfillment_cx = >::new(&infcx); - for (predicate, cause) in coroutine_interior_predicates { - let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - - if (tcx.features().unsized_locals || tcx.features().unsized_fn_params) - && let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id) - { - for field_ty in coroutine.field_tys.iter() { - fulfillment_cx.register_bound( - &infcx, - param_env, - field_ty.ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), - ObligationCause::new( - field_ty.source_info.span, - def_id, - ObligationCauseCode::SizedCoroutineInterior(def_id), - ), - ); - } + let ocx = ObligationCtxt::new(&infcx); + for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { + ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate)); } - let errors = fulfillment_cx.select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); debug!(?errors); if !errors.is_empty() { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index fb4a76bf089f4..eb1fa1baecca0 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -208,11 +208,11 @@ pub fn check_intrinsic_type( Ty::new_tup(tcx, &[param(0), tcx.types.bool]), ), "load" => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), - "store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)), + "store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit), "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), - "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)), + "fence" | "singlethreadfence" => (0, Vec::new(), tcx.types.unit), op => { tcx.dcx().emit_err(UnrecognizedAtomicOperation { span, op }); return; @@ -224,7 +224,7 @@ pub fn check_intrinsic_type( let (n_tps, n_cts, inputs, output) = match intrinsic_name { sym::abort => (0, 0, vec![], tcx.types.never), sym::unreachable => (0, 0, vec![], tcx.types.never), - sym::breakpoint => (0, 0, vec![], Ty::new_unit(tcx)), + sym::breakpoint => (0, 0, vec![], tcx.types.unit), sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { (1, 0, vec![], tcx.types.usize) } @@ -235,14 +235,14 @@ pub fn check_intrinsic_type( sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), sym::assert_inhabited | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => (1, 0, vec![], Ty::new_unit(tcx)), - sym::forget => (1, 0, vec![param(0)], Ty::new_unit(tcx)), + | sym::assert_mem_uninitialized_valid => (1, 0, vec![], tcx.types.unit), + sym::forget => (1, 0, vec![param(0)], tcx.types.unit), sym::transmute | sym::transmute_unchecked => (2, 0, vec![param(0)], param(1)), sym::prefetch_read_data | sym::prefetch_write_data | sym::prefetch_read_instruction | sym::prefetch_write_instruction => { - (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], Ty::new_unit(tcx)) + (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], tcx.types.unit) } sym::needs_drop => (1, 0, vec![], tcx.types.bool), @@ -270,7 +270,7 @@ pub fn check_intrinsic_type( Ty::new_mut_ptr(tcx, param(0)), tcx.types.usize, ], - Ty::new_unit(tcx), + tcx.types.unit, ), sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( 1, @@ -280,7 +280,7 @@ pub fn check_intrinsic_type( Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize, ], - Ty::new_unit(tcx), + tcx.types.unit, ), sym::compare_bytes => { let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8); @@ -290,7 +290,7 @@ pub fn check_intrinsic_type( 1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), tcx.types.u8, tcx.types.usize], - Ty::new_unit(tcx), + tcx.types.unit, ), sym::sqrtf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), @@ -409,16 +409,14 @@ pub fn check_intrinsic_type( (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) } sym::volatile_store | sym::unaligned_volatile_store => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } - sym::ctpop - | sym::ctlz - | sym::ctlz_nonzero - | sym::cttz - | sym::cttz_nonzero - | sym::bswap - | sym::bitreverse => (1, 0, vec![param(0)], param(0)), + sym::ctpop | sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => { + (1, 0, vec![param(0)], tcx.types.u32) + } + + sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), sym::three_way_compare => { (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span))) @@ -442,7 +440,7 @@ pub fn check_intrinsic_type( 0, 1, vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], - Ty::new_unit(tcx), + tcx.types.unit, ), sym::ptr_offset_from => ( @@ -461,7 +459,7 @@ pub fn check_intrinsic_type( (1, 0, vec![param(0), param(0)], param(0)) } sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)), - sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), param(0)], param(0)), + sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)), sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { (1, 0, vec![param(0), param(0)], param(0)) } @@ -479,16 +477,16 @@ pub fn check_intrinsic_type( | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)), + sym::assume => (0, 1, vec![tcx.types.bool], tcx.types.unit), sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } - sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], Ty::new_unit(tcx)), + sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -513,14 +511,14 @@ pub fn check_intrinsic_type( let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8], - Ty::new_unit(tcx), + tcx.types.unit, false, hir::Unsafety::Normal, Abi::Rust, )); let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8, mut_u8], - Ty::new_unit(tcx), + tcx.types.unit, false, hir::Unsafety::Normal, Abi::Rust, @@ -534,25 +532,25 @@ pub fn check_intrinsic_type( } sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { - Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], Ty::new_unit(tcx)), - None => bug!("`va_list` language item needed for C-variadic intrinsics"), + Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], tcx.types.unit), + None => bug!("`va_list` lang item needed for C-variadic intrinsics"), }, sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { Some((va_list_ref_ty, va_list_ty)) => { let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); - (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx)) + (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) } - None => bug!("`va_list` language item needed for C-variadic intrinsics"), + None => bug!("`va_list` lang item needed for C-variadic intrinsics"), }, sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) { Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)), - None => bug!("`va_list` language item needed for C-variadic intrinsics"), + None => bug!("`va_list` lang item needed for C-variadic intrinsics"), }, sym::nontemporal_store => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)) + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } sym::raw_eq => { @@ -572,7 +570,7 @@ pub fn check_intrinsic_type( sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { - (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) + (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) } // This type check is not particularly useful, but the `where` bounds @@ -625,8 +623,8 @@ pub fn check_intrinsic_type( sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)), sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), - sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), - sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)), + sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), + sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)), sym::simd_cast diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c26f982fa473c..5b127e0bf496a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,6 +2,7 @@ use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use crate::errors; +use crate::fluent_generated as fluent; use hir::intravisit::Visitor; use rustc_ast as ast; @@ -1636,10 +1637,6 @@ fn check_fn_or_method<'tcx>( } } -const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ - `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ - of the previous types except `Self`)"; - #[instrument(level = "debug", skip(wfcx))] fn check_method_receiver<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, @@ -1675,7 +1672,7 @@ fn check_method_receiver<'tcx>( if tcx.features().arbitrary_self_types { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - return Err(e0307(tcx, span, receiver_ty)); + return Err(tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })); } } else { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { @@ -1690,24 +1687,17 @@ fn check_method_receiver<'tcx>( the `arbitrary_self_types` feature", ), ) - .with_help(HELP_FOR_SELF_TYPE) + .with_help(fluent::hir_analysis_invalid_receiver_ty_help) .emit() } else { // Report error; would not have worked with `arbitrary_self_types`. - e0307(tcx, span, receiver_ty) + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) }); } } Ok(()) } -fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed { - struct_span_code_err!(tcx.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}") - .with_note("type of `self` must be `Self` or a type that dereferences to it") - .with_help(HELP_FOR_SELF_TYPE) - .emit() -} - /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 5585d2e069c59..819e0925f68df 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -2,14 +2,20 @@ //! crate or pertains to a type defined in this crate. use crate::errors; + +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt}; -use rustc_span::def_id::LocalDefId; -use rustc_span::Span; -use rustc_trait_selection::traits::{self, IsFirstInputType}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; +use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode}; +use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt}; -#[instrument(skip(tcx), level = "debug")] +#[instrument(level = "debug", skip(tcx))] pub(crate) fn orphan_check_impl( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, @@ -17,31 +23,23 @@ pub(crate) fn orphan_check_impl( let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); trait_ref.error_reported()?; - let trait_def_id = trait_ref.def_id; - - match traits::orphan_check(tcx, impl_def_id.to_def_id()) { + match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) { Ok(()) => {} - Err(err) => { - let item = tcx.hir().expect_item(impl_def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { - bug!("{:?} is not an impl: {:?}", impl_def_id, item); - }; - let tr = impl_.of_trait.as_ref().unwrap(); - let sp = tcx.def_span(impl_def_id); - - emit_orphan_check_error( - tcx, - sp, - item.span, - tr.path.span, - trait_ref, - impl_.self_ty.span, - impl_.generics, - err, - )? - } + Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) { + Ok(()) => match err { + OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => { + lint_uncovered_ty_params(tcx, uncovered_ty_params, impl_def_id) + } + OrphanCheckErr::NonLocalInputType(_) => { + bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") + } + }, + Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), + }, } + let trait_def_id = trait_ref.def_id; + // In addition to the above rules, we restrict impls of auto traits // so that they can only be implemented on nominal types, such as structs, // enums or foreign types. To see why this restriction exists, consider the @@ -186,13 +184,13 @@ pub(crate) fn orphan_check_impl( // type This = T; // } // impl AutoTrait for ::This {} - AliasKind::Projection => "associated type", + ty::Projection => "associated type", // type Foo = (impl Sized, bool) // impl AutoTrait for Foo {} - AliasKind::Weak => "type alias", + ty::Weak => "type alias", // type Opaque = impl Trait; // impl AutoTrait for Opaque {} - AliasKind::Opaque => "opaque type", + ty::Opaque => "opaque type", // ``` // struct S(T); // impl S { @@ -201,7 +199,7 @@ pub(crate) fn orphan_check_impl( // impl AutoTrait for S::This {} // ``` // FIXME(inherent_associated_types): The example code above currently leads to a cycle - AliasKind::Inherent => "associated type", + ty::Inherent => "associated type", }; (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } @@ -275,34 +273,126 @@ pub(crate) fn orphan_check_impl( Ok(()) } +/// Checks the coherence orphan rules. +/// +/// `impl_def_id` should be the `DefId` of a trait impl. +/// +/// To pass, either the trait must be local, or else two conditions must be satisfied: +/// +/// 1. All type parameters in `Self` must be "covered" by some local type constructor. +/// 2. Some local type must appear in `Self`. +#[instrument(level = "debug", skip(tcx), ret)] +fn orphan_check<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: LocalDefId, + mode: OrphanCheckMode, +) -> Result<(), OrphanCheckErr<'tcx, FxIndexSet>> { + // We only accept this routine to be invoked on implementations + // of a trait, not inherent implementations. + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + debug!(trait_ref = ?trait_ref.skip_binder()); + + // If the *trait* is local to the crate, ok. + if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() { + debug!("trait {def_id:?} is local to current crate"); + return Ok(()); + } + + // (1) Instantiate all generic params with fresh inference vars. + let infcx = tcx.infer_ctxt().intercrate(true).build(); + let cause = traits::ObligationCause::dummy(); + let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id()); + let trait_ref = trait_ref.instantiate(tcx, args); + + let lazily_normalize_ty = |user_ty: Ty<'tcx>| { + let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) }; + + let ocx = traits::ObligationCtxt::new(&infcx); + let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), user_ty); + let ty = infcx.resolve_vars_if_possible(ty); + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + return Ok(user_ty); + } + + let ty = if infcx.next_trait_solver() { + let mut fulfill_cx = >::new(&infcx); + infcx + .at(&cause, ty::ParamEnv::empty()) + .structurally_normalize(ty, &mut *fulfill_cx) + .map(|ty| infcx.resolve_vars_if_possible(ty)) + .unwrap_or(ty) + } else { + ty + }; + + Ok(ty) + }; + + let Ok(result) = traits::orphan_check_trait_ref::( + &infcx, + trait_ref, + traits::InCrate::Local { mode }, + lazily_normalize_ty, + ) else { + unreachable!() + }; + + // (2) Try to map the remaining inference vars back to generic params. + result.map_err(|err| match err { + OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => { + let mut collector = + UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() }; + uncovered.visit_with(&mut collector); + // FIXME(fmease): This is very likely reachable. + debug_assert!(!collector.uncovered_params.is_empty()); + + OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { + uncovered: collector.uncovered_params, + local_ty, + }) + } + OrphanCheckErr::NonLocalInputType(tys) => { + let generics = tcx.generics_of(impl_def_id); + let tys = tys + .into_iter() + .map(|(ty, is_target_ty)| { + (ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty) + }) + .collect(); + OrphanCheckErr::NonLocalInputType(tys) + } + }) +} + fn emit_orphan_check_error<'tcx>( tcx: TyCtxt<'tcx>, - sp: Span, - full_impl_span: Span, - trait_span: Span, trait_ref: ty::TraitRef<'tcx>, - self_ty_span: Span, - generics: &hir::Generics<'tcx>, - err: traits::OrphanCheckErr<'tcx>, -) -> Result { - let self_ty = trait_ref.self_ty(); - Err(match err { + impl_def_id: LocalDefId, + err: traits::OrphanCheckErr<'tcx, FxIndexSet>, +) -> ErrorGuaranteed { + match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - let mut diag = tcx.dcx().create_err(match self_ty.kind() { - ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () }, - _ if self_ty.is_primitive() => { - errors::OnlyCurrentTraits::Primitive { span: sp, note: () } + let item = tcx.hir().expect_item(impl_def_id); + let impl_ = item.expect_impl(); + let hir_trait_ref = impl_.of_trait.as_ref().unwrap(); + + let span = tcx.def_span(impl_def_id); + let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() { + ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () }, + _ if trait_ref.self_ty().is_primitive() => { + errors::OnlyCurrentTraits::Primitive { span, note: () } } - _ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () }, + _ => errors::OnlyCurrentTraits::Arbitrary { span, note: () }, }); for &(mut ty, is_target_ty) in &tys { let span = if matches!(is_target_ty, IsFirstInputType::Yes) { // Point at `D` in `impl for C in D` - self_ty_span + impl_.self_ty.span } else { // Point at `C` in `impl for C in D` - trait_span + hir_trait_ref.path.span }; ty = tcx.erase_regions(ty); @@ -354,12 +444,12 @@ fn emit_orphan_check_error<'tcx>( diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span }); } ty::RawPtr(ptr_ty, mutbl) => { - if !self_ty.has_param() { + if !trait_ref.self_ty().has_param() { diag.subdiagnostic( tcx.dcx(), errors::OnlyCurrentTraitsPointerSugg { - wrapper_span: self_ty_span, - struct_span: full_impl_span.shrink_to_lo(), + wrapper_span: impl_.self_ty.span, + struct_span: item.span.shrink_to_lo(), mut_key: mutbl.prefix_str(), ptr_ty, }, @@ -387,23 +477,112 @@ fn emit_orphan_check_error<'tcx>( diag.emit() } - traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { - let mut sp = sp; - for param in generics.params { - if param.name.ident().to_string() == param_ty.to_string() { - sp = param.span; - } - } + traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => { + let mut reported = None; + for param_def_id in uncovered { + let span = tcx.def_ident_span(param_def_id).unwrap(); + let name = tcx.item_name(param_def_id); - match local_type { - Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal { - span: sp, - note: (), - param_ty, - local_type, - }), - None => tcx.dcx().emit_err(errors::TyParamSome { span: sp, note: (), param_ty }), + reported.get_or_insert(match local_ty { + Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal { + span, + note: (), + param: name, + local_type, + }), + None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }), + }); } + reported.unwrap() // FIXME(fmease): This is very likely reachable. } - }) + } +} + +fn lint_uncovered_ty_params<'tcx>( + tcx: TyCtxt<'tcx>, + UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<'tcx, FxIndexSet>, + impl_def_id: LocalDefId, +) { + let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); + + for param_def_id in uncovered { + let span = tcx.def_ident_span(param_def_id).unwrap(); + let name = tcx.item_name(param_def_id); + + match local_ty { + Some(local_type) => tcx.emit_node_span_lint( + UNCOVERED_PARAM_IN_PROJECTION, + hir_id, + span, + errors::TyParamFirstLocalLint { span, note: (), param: name, local_type }, + ), + None => tcx.emit_node_span_lint( + UNCOVERED_PARAM_IN_PROJECTION, + hir_id, + span, + errors::TyParamSomeLint { span, note: (), param: name }, + ), + }; + } +} + +struct UncoveredTyParamCollector<'cx, 'tcx> { + infcx: &'cx InferCtxt<'tcx>, + uncovered_params: FxIndexSet, +} + +impl<'tcx> TypeVisitor> for UncoveredTyParamCollector<'_, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { + return; + } + let Some(origin) = self.infcx.type_var_origin(ty) else { + return ty.super_visit_with(self); + }; + if let Some(def_id) = origin.param_def_id { + self.uncovered_params.insert(def_id); + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { + if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { + ct.super_visit_with(self) + } + } +} + +struct TyVarReplacer<'cx, 'tcx> { + infcx: &'cx InferCtxt<'tcx>, + generics: &'tcx ty::Generics, +} + +impl<'cx, 'tcx> TypeFolder> for TyVarReplacer<'cx, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { + return ty; + } + let Some(origin) = self.infcx.type_var_origin(ty) else { + return ty.super_fold_with(self); + }; + if let Some(def_id) = origin.param_def_id { + // The generics of an `impl` don't have a parent, we can index directly. + let index = self.generics.param_def_id_to_index[&def_id]; + let name = self.generics.params[index as usize].name; + + Ty::new_param(self.infcx.tcx, index, name) + } else { + ty + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if !ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { + return ct; + } + ct.super_fold_with(self) + } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 1085caa310b6d..0f0736f87568b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -386,6 +386,8 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { let ty = self.tcx.fold_regions(ty, |r, _| match *r { + rustc_type_ir::RegionKind::ReStatic => r, + // This is never reached in practice. If it ever is reached, // `ReErased` should be changed to `ReStatic`, and any other region // left alone. @@ -992,7 +994,7 @@ fn lower_variant( .inspect(|f| { has_unnamed_fields |= f.ident.name == kw::Underscore; // We only check named ADT here because anonymous ADTs are checked inside - // the nammed ADT in which they are defined. + // the named ADT in which they are defined. if !is_anonymous { field_uniqueness_check_ctx.check_field(f); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 867ee772a30a2..1c99713b3ae18 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1355,29 +1355,54 @@ pub struct CrossCrateTraitsDefined { pub traits: String, } +// FIXME(fmease): Deduplicate: + #[derive(Diagnostic)] #[diag(hir_analysis_ty_param_first_local, code = E0210)] #[note] -pub struct TyParamFirstLocal<'a> { +pub struct TyParamFirstLocal<'tcx> { #[primary_span] #[label] pub span: Span, #[note(hir_analysis_case_note)] pub note: (), - pub param_ty: Ty<'a>, - pub local_type: Ty<'a>, + pub param: Symbol, + pub local_type: Ty<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_ty_param_first_local, code = E0210)] +#[note] +pub struct TyParamFirstLocalLint<'tcx> { + #[label] + pub span: Span, + #[note(hir_analysis_case_note)] + pub note: (), + pub param: Symbol, + pub local_type: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(hir_analysis_ty_param_some, code = E0210)] #[note] -pub struct TyParamSome<'a> { +pub struct TyParamSome { #[primary_span] #[label] pub span: Span, #[note(hir_analysis_only_note)] pub note: (), - pub param_ty: Ty<'a>, + pub param: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_ty_param_some, code = E0210)] +#[note] +pub struct TyParamSomeLint { + #[label] + pub span: Span, + #[note(hir_analysis_only_note)] + pub note: (), + pub param: Symbol, } #[derive(Diagnostic)] @@ -1641,3 +1666,13 @@ pub struct NonConstRange { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_invalid_receiver_ty, code = E0307)] +#[note] +#[help(hir_analysis_invalid_receiver_ty_help)] +pub struct InvalidReceiverTy<'tcx> { + #[primary_span] + pub span: Span, + pub receiver_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 822bf95305fc0..8e64a9425bb9f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; use rustc_middle::query::Key; +use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, suggest_constraining_type_param}; use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{Binder, TraitRef}; @@ -1200,12 +1201,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Emits an error regarding forbidden type binding associations pub fn prohibit_assoc_item_binding( tcx: TyCtxt<'_>, - span: Span, - segment: Option<(&hir::PathSegment<'_>, Span)>, + binding: &hir::TypeBinding<'_>, + segment: Option<(DefId, &hir::PathSegment<'_>, Span)>, ) -> ErrorGuaranteed { - tcx.dcx().emit_err(AssocTypeBindingNotAllowed { - span, - fn_trait_expansion: if let Some((segment, span)) = segment + let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed { + span: binding.span, + fn_trait_expansion: if let Some((_, segment, span)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar { Some(ParenthesizedFnTraitExpansion { @@ -1215,7 +1216,109 @@ pub fn prohibit_assoc_item_binding( } else { None }, - }) + }); + + // Emit a suggestion to turn the assoc item binding into a generic arg + // if the relevant item has a generic param whose name matches the binding name; + // otherwise suggest the removal of the binding. + if let Some((def_id, segment, _)) = segment + && segment.args().parenthesized == hir::GenericArgsParentheses::No + && let hir::TypeBindingKind::Equality { term } = binding.kind + { + // Suggests removal of the offending binding + let suggest_removal = |e: &mut Diag<'_>| { + let bindings = segment.args().bindings; + let args = segment.args().args; + let binding_span = binding.span; + + // Compute the span to remove based on the position + // of the binding. We do that as follows: + // 1. Find the index of the binding in the list of bindings + // 2. Locate the spans preceding and following the binding. + // If it's the first binding the preceding span would be + // that of the last arg + // 3. Using this information work out whether the span + // to remove will start from the end of the preceding span, + // the start of the next span or will simply be the + // span encomassing everything within the generics brackets + + let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id) + else { + bug!("a type binding exists but its HIR ID not found in generics"); + }; + + let preceding_span = if binding_index > 0 { + Some(bindings[binding_index - 1].span) + } else { + args.last().map(|a| a.span()) + }; + + let next_span = if binding_index < bindings.len() - 1 { + Some(bindings[binding_index + 1].span) + } else { + None + }; + + let removal_span = match (preceding_span, next_span) { + (Some(prec), _) => binding_span.with_lo(prec.hi()), + (None, Some(next)) => binding_span.with_hi(next.lo()), + (None, None) => { + let Some(generics_span) = segment.args().span_ext() else { + bug!("a type binding exists but generic span is empty"); + }; + + generics_span + } + }; + + // Now emit the suggestion + if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) { + e.span_suggestion_verbose( + removal_span, + "consider removing this type binding", + suggestion, + Applicability::MaybeIncorrect, + ); + } + }; + + // Suggest replacing the associated item binding with a generic argument. + // i.e., replacing `<..., T = A, ...>` with `<..., A, ...>`. + let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) { + e.span_suggestion_verbose( + binding.span, + format!("to use `{snippet}` as a generic argument specify it directly"), + snippet, + Applicability::MaybeIncorrect, + ); + } + }; + + // Check if the type has a generic param with the + // same name as the assoc type name in type binding + let generics = tcx.generics_of(def_id); + let matching_param = + generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str()); + + // Now emit the appropriate suggestion + if let Some(matching_param) = matching_param { + match (&matching_param.kind, term) { + (GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => { + suggest_direct_use(&mut err, ty.span); + } + (GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => { + let span = tcx.hir().span(c.hir_id); + suggest_direct_use(&mut err, span); + } + _ => suggest_removal(&mut err), + } + } else { + suggest_removal(&mut err); + } + } + + err.emit() } pub(crate) fn fn_trait_to_string( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index dd76862451c6f..e6a7dfa759c8e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -454,7 +454,7 @@ pub(crate) fn check_generic_arg_count( if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { - prohibit_assoc_item_binding(tcx, b.span, None); + prohibit_assoc_item_binding(tcx, b, None); } let explicit_late_bound = diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 0d5a295ca9669..f7213442ac2dd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -323,7 +323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ); if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span))); + prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span))); } args } @@ -620,7 +620,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ); if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span))); + prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span))); } args } @@ -765,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { constness, ); if let Some(b) = trait_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b.span, Some((trait_segment, span))); + prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span))); } ty::TraitRef::new(self.tcx(), trait_def_id, generic_args) } @@ -1544,7 +1544,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for segment in segments { // Only emit the first error to avoid overloading the user with error messages. if let Some(b) = segment.args().bindings.first() { - return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None)); + return Err(prohibit_assoc_item_binding(self.tcx(), b, None)); } } @@ -1964,11 +1964,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("recursive delegation"); } - let sig = self.tcx().fn_sig(sig_id).instantiate_identity(); - if sig.output().has_opaque_types() { - try_emit("delegation to a function with opaque type"); - } - let sig_generics = self.tcx().generics_of(sig_id); let parent = self.tcx().parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); @@ -1991,29 +1986,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("delegation to a trait method from a free function"); } - if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes { - try_emit("delegation to async functions"); - } - - if self.tcx().constness(sig_id) == hir::Constness::Const { - try_emit("delegation to const functions"); - } - - if sig.c_variadic() { - try_emit("delegation to variadic functions"); - // variadic functions are also `unsafe` and `extern "C"`. - // Do not emit same error multiple times. - return error_occured; - } - - if let hir::Unsafety::Unsafe = sig.unsafety() { - try_emit("delegation to unsafe functions"); - } - - if abi::Abi::Rust != sig.abi() { - try_emit("delegation to non Rust ABI functions"); - } - error_occured } @@ -2398,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_ty(output) } } - hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx), + hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, }; debug!(?output_ty); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index c374f9762d69b..66b86c9eb02a3 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -63,7 +63,6 @@ This API is completely unstable and subject to change. #![feature(rustdoc_internals)] #![allow(internal_features)] #![feature(control_flow_enum)] -#![feature(generic_nonzero)] #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 07b4948872dd8..0560d0d902a3f 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -99,6 +99,17 @@ hir_typeck_lossy_provenance_ptr2int = hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function + .help = specify the type explicitly +hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference + .help = specify the type explicitly +hir_typeck_never_type_fallback_flowing_into_unsafe_method = never type fallback affects this call to an `unsafe` method + .help = specify the type explicitly +hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback affects this `unsafe` function + .help = specify the type explicitly +hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access + .help = specify the type explicitly + hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> [true] {""} *[other] {" "}in the current scope diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 334a424d2e26c..4ff6678fc9144 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // us to give better error messages (pointing to a usually better // arm for inconsistent arms or to the whole match when a `()` type // is required). - Expectation::ExpectHasType(ety) if ety != Ty::new_unit(self.tcx) => ety, + Expectation::ExpectHasType(ety) if ety != tcx.types.unit => ety, _ => self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }), }; CoerceMany::with_coercion_sites(coerce_first, arms) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index a64d3b9633f26..dfd0b7c2945c4 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -38,8 +38,11 @@ pub fn check_legal_trait_for_method_call( receiver: Option, expr_span: Span, trait_id: DefId, + body_id: DefId, ) -> Result<(), ErrorGuaranteed> { - if tcx.lang_items().drop_trait() == Some(trait_id) { + if tcx.lang_items().drop_trait() == Some(trait_id) + && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id) + { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { errors::ExplicitDestructorCallSugg::Snippet { lo: expr_span.shrink_to_lo(), diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b0d1b6655dbf1..b106eca59c473 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi}; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::RegionVariableOrigin; +use rustc_infer::traits::WellFormedLoc; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; @@ -71,6 +72,18 @@ pub(super) fn check_fn<'a, 'tcx>( let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // We checked the root's signature during wfcheck, but not the child. + if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { + fcx.register_wf_obligation( + param_ty.into(), + param.span, + traits::WellFormed(Some(WellFormedLoc::Param { + function: fn_def_id, + param_idx: idx, + })), + ); + } + // Check the pattern. let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx)); let ty_span = ty.map(|ty| ty.span); @@ -108,7 +121,13 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::DefaultReturn(_) => body.value.span, hir::FnRetTy::Return(ty) => ty.span, }; + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + // We checked the root's signature during wfcheck, but not the child. + if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::WellFormed(None)); + } + fcx.is_whole_body.set(true); fcx.check_return_expr(body.value, false); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d6704d9e44f9b..4883c7aff8bc4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -342,7 +342,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates( Ty::new_var(self.tcx, self.root_var(vid)), closure_kind, - self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)), + self.obligations_for_self_ty(vid) + .into_iter() + .map(|obl| (obl.predicate, obl.cause.span)), ), ty::FnPtr(sig) => match closure_kind { hir::ClosureKind::Closure => { @@ -889,7 +891,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { - self.obligations_for_self_ty(ret_vid).find_map(|obligation| { + self.obligations_for_self_ty(ret_vid).into_iter().find_map(|obligation| { get_future_output(obligation.predicate, obligation.cause.span) })? } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9ebb5f95f05fd..825276aef421c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // are the same function and their parameters have a LUB. match self.commit_if_ok(|_| { self.at(cause, self.param_env).lub( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, prev_ty, new_ty, ) @@ -1462,7 +1462,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx, cause, None, - Ty::new_unit(fcx.tcx), + fcx.tcx.types.unit, augment_error, label_unit_as_expected, ) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d6d22a43fe0b8..618d90a07ec29 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { [candidate] => format!( "the method of the same name on {} `{}`", match candidate.kind { - probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for", + probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for", _ => "trait", }, self.tcx.def_path_str(candidate.item.container_id(self.tcx)) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3dc9c7b86f713..ba8f246fd8d24 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -164,6 +164,25 @@ pub struct MissingParenthesesInRange { pub add_missing_parentheses: Option, } +#[derive(LintDiagnostic)] +pub enum NeverTypeFallbackFlowingIntoUnsafe { + #[help] + #[diag(hir_typeck_never_type_fallback_flowing_into_unsafe_call)] + Call, + #[help] + #[diag(hir_typeck_never_type_fallback_flowing_into_unsafe_method)] + Method, + #[help] + #[diag(hir_typeck_never_type_fallback_flowing_into_unsafe_path)] + Path, + #[help] + #[diag(hir_typeck_never_type_fallback_flowing_into_unsafe_union_field)] + UnionField, + #[help] + #[diag(hir_typeck_never_type_fallback_flowing_into_unsafe_deref)] + Deref, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_typeck_add_missing_parentheses_in_range, @@ -191,7 +210,7 @@ impl Subdiagnostic for TypeMismatchFruTypo { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); @@ -370,7 +389,7 @@ impl Subdiagnostic for RemoveSemiForCoerce { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); @@ -546,7 +565,7 @@ impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { match self { CastUnknownPointerSub::To(span) => { @@ -632,7 +651,6 @@ pub enum SuggestBoxingForReturnImplTrait { ends: Vec, }, } - #[derive(LintDiagnostic)] #[diag(hir_typeck_dereferencing_mut_binding)] pub struct DereferencingMutBinding { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 8923137fdd82d..8b1ea7c952cb1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1,6 +1,6 @@ //! Type checking expressions. //! -//! See `mod.rs` for more context on type checking in general. +//! See [`rustc_hir_analysis::check`] for more context on type checking in general. use crate::cast; use crate::coercion::CoerceMany; @@ -654,7 +654,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. - e_ty = Ty::new_unit(tcx); + e_ty = tcx.types.unit; cause = self.misc(expr.span); } @@ -1133,7 +1133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The expected type is `bool` but this will result in `()` so we can reasonably // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. // The likely cause of this is `if foo = bar { .. }`. - let actual_ty = Ty::new_unit(self.tcx); + let actual_ty = self.tcx.types.unit; let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); let lhs_ty = self.check_expr(lhs); let rhs_ty = self.check_expr(rhs); @@ -1256,7 +1256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Err(guar) = (lhs_ty, rhs_ty).error_reported() { Ty::new_error(self.tcx, guar) } else { - Ty::new_unit(self.tcx) + self.tcx.types.unit } } @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if ctxt.coerce.is_none() && !ctxt.may_break { self.dcx().span_bug(body.span, "no coercion, but loop may not break"); } - ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) + ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.types.unit) } /// Checks a method call. @@ -2697,7 +2697,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn point_at_param_definition(&self, err: &mut Diag<'_>, param: ty::ParamTy) { let generics = self.tcx.generics_of(self.body_id); - let generic_param = generics.type_param(¶m, self.tcx); + let generic_param = generics.type_param(param, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { return; } @@ -3174,7 +3174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.dcx().emit_err(YieldExprOutsideOfCoroutine { span: expr.span }); // Avoid expressions without types during writeback (#78653). self.check_expr(value); - Ty::new_unit(self.tcx) + self.tcx.types.unit } } } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index a0a5a75d3820a..cc42e69f53827 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } } + } else if let PatKind::Deref(subpattern) = pat.kind { + // A deref pattern is a bit special: the binding mode of its inner bindings + // determines whether to borrow *at the level of the deref pattern* rather than + // borrowing the bound place (since that inner place is inside the temporary that + // stores the result of calling `deref()`/`deref_mut()` so can't be captured). + let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + let bk = ty::BorrowKind::from_mutbl(mutability); + delegate.borrow(place, discr_place.hir_id, bk); } })); } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index c0b3984e3e17d..f240a53a67974 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,11 +1,18 @@ -use crate::FnCtxt; +use std::cell::OnceCell; + +use crate::{errors, FnCtxt, TypeckRootCtxt}; use rustc_data_structures::{ graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph}, unord::{UnordBag, UnordMap, UnordSet}, }; +use rustc_hir as hir; +use rustc_hir::intravisit::Visitor; +use rustc_hir::HirId; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_session::lint; use rustc_span::DUMMY_SP; +use rustc_span::{def_id::LocalDefId, Span}; #[derive(Copy, Clone)] pub enum DivergingFallbackBehavior { @@ -335,6 +342,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // reach a member of N. If so, it falls back to `()`. Else // `!`. let mut diverging_fallback = UnordMap::with_capacity(diverging_vids.len()); + let unsafe_infer_vars = OnceCell::new(); for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); @@ -354,11 +362,51 @@ impl<'tcx> FnCtxt<'_, 'tcx> { output: infer_var_infos.items().any(|info| info.output), }; + let mut fallback_to = |ty| { + let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| { + let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id); + debug!(?unsafe_infer_vars); + unsafe_infer_vars + }); + + let affected_unsafe_infer_vars = + graph::depth_first_search_as_undirected(&coercion_graph, root_vid) + .filter_map(|x| unsafe_infer_vars.get(&x).copied()) + .collect::>(); + + for (hir_id, span, reason) in affected_unsafe_infer_vars { + self.tcx.emit_node_span_lint( + lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, + hir_id, + span, + match reason { + UnsafeUseReason::Call => { + errors::NeverTypeFallbackFlowingIntoUnsafe::Call + } + UnsafeUseReason::Method => { + errors::NeverTypeFallbackFlowingIntoUnsafe::Method + } + UnsafeUseReason::Path => { + errors::NeverTypeFallbackFlowingIntoUnsafe::Path + } + UnsafeUseReason::UnionField => { + errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField + } + UnsafeUseReason::Deref => { + errors::NeverTypeFallbackFlowingIntoUnsafe::Deref + } + }, + ); + } + + diverging_fallback.insert(diverging_ty, ty); + }; + use DivergingFallbackBehavior::*; match behavior { FallbackToUnit => { debug!("fallback to () - legacy: {:?}", diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + fallback_to(self.tcx.types.unit); } FallbackToNiko => { if found_infer_var_info.self_in_trait && found_infer_var_info.output { @@ -387,13 +435,13 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // set, see the relationship finding module in // compiler/rustc_trait_selection/src/traits/relationships.rs. debug!("fallback to () - found trait and projection: {:?}", diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + fallback_to(self.tcx.types.unit); } else if can_reach_non_diverging { debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + fallback_to(self.tcx.types.unit); } else { debug!("fallback to ! - all diverging: {:?}", diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.types.never); + fallback_to(self.tcx.types.never); } } FallbackToNever => { @@ -401,7 +449,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { "fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}", diverging_vid ); - diverging_fallback.insert(diverging_ty, self.tcx.types.never); + fallback_to(self.tcx.types.never); } NoFallback => { debug!( @@ -417,7 +465,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// Returns a graph whose nodes are (unresolved) inference variables and where /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. - fn create_coercion_graph(&self) -> VecGraph { + fn create_coercion_graph(&self) -> VecGraph { let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations @@ -436,17 +484,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // // In practice currently the two ways that this happens is // coercion and subtyping. - let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom { - (a, b) - } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate { - a_is_expected: _, - a, - b, - }) = atom - { - (a, b) - } else { - return None; + let (a, b) = match atom { + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b), + ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { + (a, b) + } + _ => return None, }; let a_vid = self.root_vid(a)?; @@ -456,6 +499,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .collect(); debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); let num_ty_vars = self.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) } @@ -464,3 +508,166 @@ impl<'tcx> FnCtxt<'_, 'tcx> { Some(self.root_var(self.shallow_resolve(ty).ty_vid()?)) } } + +#[derive(Debug, Copy, Clone)] +pub(crate) enum UnsafeUseReason { + Call, + Method, + Path, + UnionField, + Deref, +} + +/// Finds all type variables which are passed to an `unsafe` operation. +/// +/// For example, for this function `f`: +/// ```ignore (demonstrative) +/// fn f() { +/// unsafe { +/// let x /* ?X */ = core::mem::zeroed(); +/// // ^^^^^^^^^^^^^^^^^^^ -- hir_id, span, reason +/// +/// let y = core::mem::zeroed::>(); +/// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- hir_id, span, reason +/// } +/// } +/// ``` +/// +/// `compute_unsafe_infer_vars` will return `{ id(?X) -> (hir_id, span, Call) }` +fn compute_unsafe_infer_vars<'a, 'tcx>( + root_ctxt: &'a TypeckRootCtxt<'tcx>, + body_id: LocalDefId, +) -> UnordMap { + let body_id = + root_ctxt.tcx.hir().maybe_body_owned_by(body_id).expect("body id must have an owner"); + let body = root_ctxt.tcx.hir().body(body_id); + let mut res = UnordMap::default(); + + struct UnsafeInferVarsVisitor<'a, 'tcx, 'r> { + root_ctxt: &'a TypeckRootCtxt<'tcx>, + res: &'r mut UnordMap, + } + + impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_, '_> { + fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) { + let typeck_results = self.root_ctxt.typeck_results.borrow(); + + match ex.kind { + hir::ExprKind::MethodCall(..) => { + if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id) + && let method_ty = self.root_ctxt.tcx.type_of(def_id).instantiate_identity() + && let sig = method_ty.fn_sig(self.root_ctxt.tcx) + && let hir::Unsafety::Unsafe = sig.unsafety() + { + let mut collector = InferVarCollector { + value: (ex.hir_id, ex.span, UnsafeUseReason::Method), + res: self.res, + }; + + // Collect generic arguments (incl. `Self`) of the method + typeck_results + .node_args(ex.hir_id) + .types() + .for_each(|t| t.visit_with(&mut collector)); + } + } + + hir::ExprKind::Call(func, ..) => { + let func_ty = typeck_results.expr_ty(func); + + if func_ty.is_fn() + && let sig = func_ty.fn_sig(self.root_ctxt.tcx) + && let hir::Unsafety::Unsafe = sig.unsafety() + { + let mut collector = InferVarCollector { + value: (ex.hir_id, ex.span, UnsafeUseReason::Call), + res: self.res, + }; + + // Try collecting generic arguments of the function. + // Note that we do this below for any paths (that don't have to be called), + // but there we do it with a different span/reason. + // This takes priority. + typeck_results + .node_args(func.hir_id) + .types() + .for_each(|t| t.visit_with(&mut collector)); + + // Also check the return type, for cases like `returns_unsafe_fn_ptr()()` + sig.output().visit_with(&mut collector); + } + } + + // Check paths which refer to functions. + // We do this, instead of only checking `Call` to make sure the lint can't be + // avoided by storing unsafe function in a variable. + hir::ExprKind::Path(_) => { + let ty = typeck_results.expr_ty(ex); + + // If this path refers to an unsafe function, collect inference variables which may affect it. + // `is_fn` excludes closures, but those can't be unsafe. + if ty.is_fn() + && let sig = ty.fn_sig(self.root_ctxt.tcx) + && let hir::Unsafety::Unsafe = sig.unsafety() + { + let mut collector = InferVarCollector { + value: (ex.hir_id, ex.span, UnsafeUseReason::Path), + res: self.res, + }; + + // Collect generic arguments of the function + typeck_results + .node_args(ex.hir_id) + .types() + .for_each(|t| t.visit_with(&mut collector)); + } + } + + hir::ExprKind::Unary(hir::UnOp::Deref, pointer) => { + if let ty::RawPtr(pointee, _) = typeck_results.expr_ty(pointer).kind() { + pointee.visit_with(&mut InferVarCollector { + value: (ex.hir_id, ex.span, UnsafeUseReason::Deref), + res: self.res, + }); + } + } + + hir::ExprKind::Field(base, _) => { + let base_ty = typeck_results.expr_ty(base); + + if base_ty.is_union() { + typeck_results.expr_ty(ex).visit_with(&mut InferVarCollector { + value: (ex.hir_id, ex.span, UnsafeUseReason::UnionField), + res: self.res, + }); + } + } + + _ => (), + }; + + hir::intravisit::walk_expr(self, ex); + } + } + + struct InferVarCollector<'r, V> { + value: V, + res: &'r mut UnordMap, + } + + impl<'tcx, V: Copy> ty::TypeVisitor> for InferVarCollector<'_, V> { + fn visit_ty(&mut self, t: Ty<'tcx>) { + if let Some(vid) = t.ty_vid() { + _ = self.res.try_insert(vid, self.value); + } else { + t.super_visit_with(self) + } + } + } + + UnsafeInferVarsVisitor { root_ctxt, res: &mut res }.visit_expr(&body.value); + + debug!(?res, "collected the following unsafe vars for {body_id:?}"); + + res +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index bd2454f6368d3..2060e08aacf97 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -3,7 +3,6 @@ use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; @@ -47,7 +46,7 @@ use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. - pub(in super::super) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { + pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { // FIXME: Combine these two 'if' expressions into one once // let chains are implemented if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { @@ -87,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(-Znext-solver): A lot of the calls to this method should // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead. #[instrument(skip(self), level = "debug", ret)] - pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { // No Infer()? Nothing needs doing. if !ty.has_non_region_infer() { debug!("no inference var, nothing needs doing"); @@ -109,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_if_possible(ty) } - pub(in super::super) fn record_deferred_call_resolution( + pub(crate) fn record_deferred_call_resolution( &self, closure_def_id: LocalDefId, r: DeferredCallResolution<'tcx>, @@ -118,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_call_resolutions.entry(closure_def_id).or_default().push(r); } - pub(in super::super) fn remove_deferred_call_resolutions( + pub(crate) fn remove_deferred_call_resolutions( &self, closure_def_id: LocalDefId, ) -> Vec> { @@ -172,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(in super::super) fn write_resolution( + pub(crate) fn write_resolution( &self, hir_id: HirId, r: Result<(DefKind, DefId), ErrorGuaranteed>, @@ -336,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Instantiates and normalizes the bounds for a given item - pub(in super::super) fn instantiate_bounds( + pub(crate) fn instantiate_bounds( &self, span: Span, def_id: DefId, @@ -349,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } - pub(in super::super) fn normalize(&self, span: Span, value: T) -> T + pub(crate) fn normalize(&self, span: Span, value: T) -> T where T: TypeFoldable>, { @@ -537,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.normalize(span, field.ty(self.tcx, args)) } - pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) { + pub(crate) fn resolve_rvalue_scopes(&self, def_id: DefId) { let scope_tree = self.tcx.region_scope_tree(def_id); let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) }; let mut typeck_results = self.typeck_results.borrow_mut(); @@ -553,7 +552,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// We must not attempt to select obligations after this method has run, or risk query cycle /// ICE. #[instrument(level = "debug", skip(self))] - pub(in super::super) fn resolve_coroutine_interiors(&self) { + pub(crate) fn resolve_coroutine_interiors(&self) { // Try selecting all obligations that are not blocked on inference variables. // Once we start unifying coroutine witnesses, trying to select obligations on them will // trigger query cycle ICEs, as doing so requires MIR. @@ -588,17 +587,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx)); - let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect(); - debug!(?obligations); - self.typeck_results - .borrow_mut() - .coroutine_interior_predicates - .insert(expr_def_id, obligations); + let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)); + self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations); } } #[instrument(skip(self), level = "debug")] - pub(in super::super) fn report_ambiguity_errors(&self) { + pub(crate) fn report_ambiguity_errors(&self) { let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self); if !errors.is_empty() { @@ -613,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Select as many obligations as we can at present. - pub(in super::super) fn select_obligations_where_possible( + pub(crate) fn select_obligations_where_possible( &self, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) { @@ -629,7 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. - pub(in super::super) fn make_overloaded_place_return_type( + pub(crate) fn make_overloaded_place_return_type( &self, method: MethodCallee<'tcx>, ) -> ty::TypeAndMut<'tcx> { @@ -640,67 +635,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } - #[instrument(skip(self), level = "debug")] - fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool { - let self_ty = self.shallow_resolve(self_ty); - debug!(?self_ty); - - match *self_ty.kind() { - ty::Infer(ty::TyVar(found_vid)) => { - let found_vid = self.root_var(found_vid); - debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); - expected_vid == found_vid - } - _ => false, - } - } - - #[instrument(skip(self), level = "debug")] - pub(in super::super) fn obligations_for_self_ty<'b>( - &'b self, - self_ty: ty::TyVid, - ) -> impl DoubleEndedIterator> + Captures<'tcx> + 'b - { - let ty_var_root = self.root_var(self_ty); - trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations()); - - self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map( - move |obligation| match &obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) - if self.self_type_matches_expected_vid( - data.projection_ty.self_ty(), - ty_var_root, - ) => - { - Some(obligation) - } - ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) - if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) => - { - Some(obligation) - } - - ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::NormalizesTo(..) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous => None, - }, - ) - } - - pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + pub(crate) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { let sized_did = self.tcx.lang_items().sized_trait(); - self.obligations_for_self_ty(self_ty).any(|obligation| { + self.obligations_for_self_ty(self_ty).into_iter().any(|obligation| { match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { Some(data.def_id()) == sized_did @@ -710,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - pub(in super::super) fn err_args(&self, len: usize) -> Vec> { + pub(crate) fn err_args(&self, len: usize) -> Vec> { let ty_error = Ty::new_misc_error(self.tcx); vec![ty_error; len] } @@ -718,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. #[instrument(skip(self, call_span), level = "debug")] - pub(in super::super) fn expected_inputs_for_expected_output( + pub(crate) fn expected_inputs_for_expected_output( &self, call_span: Span, expected_ret: Expectation<'tcx>, @@ -751,7 +688,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expect_args } - pub(in super::super) fn resolve_lang_item_path( + pub(crate) fn resolve_lang_item_path( &self, lang_item: hir::LangItem, span: Span, @@ -930,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// but we often want access to the parent function's signature. /// /// Otherwise, return false. - pub(in super::super) fn get_node_fn_decl( + pub(crate) fn get_node_fn_decl( &self, node: Node<'tcx>, ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> { @@ -1008,7 +945,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - pub(in super::super) fn note_internal_mutation_in_method( + pub(crate) fn note_internal_mutation_in_method( &self, err: &mut Diag<'_>, expr: &hir::Expr<'_>, @@ -1131,6 +1068,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, span, container_id, + self.body_id.to_def_id(), ) { self.set_tainted_by_errors(e); } @@ -1552,7 +1490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn with_breakable_ctxt R, R>( + pub(crate) fn with_breakable_ctxt R, R>( &self, id: HirId, ctxt: BreakableCtxt<'tcx>, @@ -1578,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Instantiate a QueryResponse in a probe context, without a /// good ObligationCause. - pub(in super::super) fn probe_instantiate_query_response( + pub(crate) fn probe_instantiate_query_response( &self, span: Span, original_values: &OriginalQueryValues<'tcx>, @@ -1593,7 +1531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - pub(in super::super) fn expr_in_place(&self, mut expr_id: HirId) -> bool { + pub(crate) fn expr_in_place(&self, mut expr_id: HirId) -> bool { let mut contained_in_place = false; while let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr_id) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d9e5289f6323b..e45e0884affb1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1660,7 +1660,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::StmtKind::Item(_) => {} hir::StmtKind::Expr(ref expr) => { // Check with expected type of `()`. - self.check_expr_has_type_or_error(expr, Ty::new_unit(self.tcx), |err| { + self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| { if expr.can_have_side_effects() { self.suggest_semicolon_at_end(expr.span, err); } @@ -1676,7 +1676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { - let unit = Ty::new_unit(self.tcx); + let unit = self.tcx.types.unit; let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); // if the block produces a `!` value, that can always be @@ -1794,7 +1794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk.span, blk.hir_id, expected_ty, - Ty::new_unit(self.tcx), + self.tcx.types.unit, ); } if !self.err_ctxt().consider_removing_semicolon( @@ -2144,7 +2144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { ty::Param(param) => { - let param = self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx); + let param = self.tcx.generics_of(self.body_id).type_param(param, self.tcx); if param.kind.is_synthetic() { // if it's `impl Fn() -> ..` then just fall down to the def-id based logic def_id = param.def_id; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs new file mode 100644 index 0000000000000..c2068d9f66b8f --- /dev/null +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -0,0 +1,140 @@ +//! A utility module to inspect currently ambiguous obligations in the current context. +use crate::rustc_middle::ty::TypeVisitableExt; +use crate::FnCtxt; +use rustc_infer::traits::solve::Goal; +use rustc_infer::traits::{self, ObligationCause}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; +use rustc_trait_selection::solve::inspect::ProofTreeInferCtxtExt; +use rustc_trait_selection::solve::inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Returns a list of all obligations whose self type has been unified + /// with the unconstrained type `self_ty`. + #[instrument(skip(self), level = "debug")] + pub(crate) fn obligations_for_self_ty( + &self, + self_ty: ty::TyVid, + ) -> Vec> { + if self.next_trait_solver() { + self.obligations_for_self_ty_next(self_ty) + } else { + let ty_var_root = self.root_var(self_ty); + let mut obligations = self.fulfillment_cx.borrow().pending_obligations(); + trace!("pending_obligations = {:#?}", obligations); + obligations + .retain(|obligation| self.predicate_has_self_ty(obligation.predicate, ty_var_root)); + obligations + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn predicate_has_self_ty( + &self, + predicate: ty::Predicate<'tcx>, + expected_vid: ty::TyVid, + ) -> bool { + match predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + self.type_matches_expected_vid(expected_vid, data.self_ty()) + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { + self.type_matches_expected_vid(expected_vid, data.projection_ty.self_ty()) + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous => false, + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn type_matches_expected_vid(&self, expected_vid: ty::TyVid, ty: Ty<'tcx>) -> bool { + let ty = self.shallow_resolve(ty); + debug!(?ty); + + match *ty.kind() { + ty::Infer(ty::TyVar(found_vid)) => { + self.root_var(expected_vid) == self.root_var(found_vid) + } + _ => false, + } + } + + pub(crate) fn obligations_for_self_ty_next( + &self, + self_ty: ty::TyVid, + ) -> Vec> { + let obligations = self.fulfillment_cx.borrow().pending_obligations(); + debug!(?obligations); + let mut obligations_for_self_ty = vec![]; + for obligation in obligations { + let mut visitor = NestedObligationsForSelfTy { + fcx: self, + self_ty, + obligations_for_self_ty: &mut obligations_for_self_ty, + root_cause: &obligation.cause, + }; + + let goal = Goal::new(self.tcx, obligation.param_env, obligation.predicate); + self.visit_proof_tree(goal, &mut visitor); + } + + obligations_for_self_ty.retain_mut(|obligation| { + obligation.predicate = self.resolve_vars_if_possible(obligation.predicate); + !obligation.predicate.has_placeholders() + }); + obligations_for_self_ty + } +} + +struct NestedObligationsForSelfTy<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + self_ty: ty::TyVid, + root_cause: &'a ObligationCause<'tcx>, + obligations_for_self_ty: &'a mut Vec>, +} + +impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { + type Result = (); + + fn span(&self) -> Span { + self.root_cause.span + } + + fn config(&self) -> InspectConfig { + // Using an intentionally low depth to minimize the chance of future + // breaking changes in case we adapt the approach later on. This also + // avoids any hangs for exponentially growing proof trees. + InspectConfig { max_depth: 5 } + } + + fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { + let tcx = self.fcx.tcx; + let goal = inspect_goal.goal(); + if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) { + self.obligations_for_self_ty.push(traits::Obligation::new( + tcx, + self.root_cause.clone(), + goal.param_env, + goal.predicate, + )); + } + + // If there's a unique way to prove a given goal, recurse into + // that candidate. This means that for `impl Trait for () {}` + // and a `(): Trait` goal we recurse into the impl and look at + // the nested `?0: FnOnce(u32)` goal. + if let Some(candidate) = inspect_goal.unique_applicable_candidate() { + candidate.visit_nested_no_probe(self) + } + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 080571e1a7085..794b854ca5f95 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -2,14 +2,17 @@ mod _impl; mod adjust_fulfillment_errors; mod arg_matrix; mod checks; +mod inspect_obligations; mod suggestions; +use rustc_errors::ErrorGuaranteed; + use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; use crate::fn_ctxt::checks::DivergingBlockBehavior; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; use hir::def_id::CRATE_DEF_ID; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::DiagCtxt; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 43e5ab0ed53f8..133778a416cc2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -23,7 +23,7 @@ use rustc_hir::{ }; use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::traits::{self}; +use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::print::with_no_trimmed_paths; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 121815ecc0ba5..8bc070bcd36cd 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -66,7 +66,7 @@ use rustc_middle::query::Providers; use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -84,21 +84,6 @@ macro_rules! type_error_struct { }) } -fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let typeck_root_def_id = tcx.typeck_root_def_id(def_id); - if typeck_root_def_id != def_id { - return tcx.has_typeck_results(typeck_root_def_id); - } - - if let Some(def_id) = def_id.as_local() { - tcx.hir_node_by_def_id(def_id).body_id().is_some() - } else { - false - } -} - fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet { &tcx.typeck(def_id).used_trait_imports } @@ -429,11 +414,5 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { pub fn provide(providers: &mut Providers) { method::provide(providers); - *providers = Providers { - typeck, - diagnostic_only_typeck, - has_typeck_results, - used_trait_imports, - ..*providers - }; + *providers = Providers { typeck, diagnostic_only_typeck, used_trait_imports, ..*providers }; } diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 859877962fe78..b44c2345933fb 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -711,13 +711,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_pattern_(place_with_id, subpat, op)?; } - PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => { + PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. let subplace = self.cat_deref(pat, place_with_id)?; self.cat_pattern_(subplace, subpat, op)?; } + PatKind::Deref(subpat) => { + let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + let re_erased = self.tcx().lifetimes.re_erased; + let ty = self.pat_ty_adjusted(subpat)?; + let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability); + // A deref pattern generates a temporary. + let place = self.cat_rvalue(pat.hir_id, ty); + self.cat_pattern_(place, subpat, op)?; + } PatKind::Slice(before, ref slice, after) => { let Some(element_ty) = place_with_id.place.ty().builtin_index() else { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 02759064abd42..d57015282de9e 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -628,6 +628,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Some(self.self_expr.span), self.call_expr.span, trait_def_id, + self.body_id.to_def_id(), ) { self.set_tainted_by_errors(e); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2876e0b49db22..8a7ebd6478b13 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::lint; use rustc_span::def_id::DefId; @@ -37,7 +37,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefStepsResult, }; use rustc_trait_selection::traits::query::CanonicalTyGoal; -use rustc_trait_selection::traits::NormalizeExt; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::cell::RefCell; use std::cmp::max; @@ -99,39 +99,6 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { #[derive(Debug, Clone)] pub(crate) struct Candidate<'tcx> { - // Candidates are (I'm not quite sure, but they are mostly) basically - // some metadata on top of a `ty::AssocItem` (without args). - // - // However, method probing wants to be able to evaluate the predicates - // for a function with the args applied - for example, if a function - // has `where Self: Sized`, we don't want to consider it unless `Self` - // is actually `Sized`, and similarly, return-type suggestions want - // to consider the "actual" return type. - // - // The way this is handled is through `xform_self_ty`. It contains - // the receiver type of this candidate, but `xform_self_ty`, - // `xform_ret_ty` and `kind` (which contains the predicates) have the - // generic parameters of this candidate instantiated with the *same set* - // of inference variables, which acts as some weird sort of "query". - // - // When we check out a candidate, we require `xform_self_ty` to be - // a subtype of the passed-in self-type, and this equates the type - // variables in the rest of the fields. - // - // For example, if we have this candidate: - // ``` - // trait Foo { - // fn foo(&self) where Self: Sized; - // } - // ``` - // - // Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain - // the predicate `?X: Sized`, so if we are evaluating `Foo` for a - // the receiver `&T`, we'll do the subtyping which will make `?X` - // get the right value, then when we evaluate the predicate we'll check - // if `T: Sized`. - xform_self_ty: Ty<'tcx>, - xform_ret_ty: Option>, pub(crate) item: ty::AssocItem, pub(crate) kind: CandidateKind<'tcx>, pub(crate) import_ids: SmallVec<[LocalDefId; 1]>, @@ -139,17 +106,10 @@ pub(crate) struct Candidate<'tcx> { #[derive(Debug, Clone)] pub(crate) enum CandidateKind<'tcx> { - InherentImplCandidate( - GenericArgsRef<'tcx>, - // Normalize obligations - Vec>, - ), - ObjectCandidate, - TraitCandidate(ty::TraitRef<'tcx>), - WhereClauseCandidate( - // Trait - ty::PolyTraitRef<'tcx>, - ), + InherentImplCandidate(DefId), + ObjectCandidate(ty::PolyTraitRef<'tcx>), + TraitCandidate(ty::PolyTraitRef<'tcx>), + WhereClauseCandidate(ty::PolyTraitRef<'tcx>), } #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -743,42 +703,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.record_static_candidate(CandidateSource::Impl(impl_def_id)); continue; } - - let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id); - let impl_ty = impl_ty.instantiate(self.tcx, impl_args); - - debug!("impl_ty: {:?}", impl_ty); - - // Determine the receiver type that the method itself expects. - let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args); - debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); - - // We can't use `FnCtxt::normalize` as it will pollute the - // fcx's fulfillment context after this probe is over. - // - // Note: we only normalize `xform_self_ty` here since the normalization - // of the return type can lead to inference results that prohibit - // valid candidates from being found, see issue #85671 - // - // FIXME Postponing the normalization of the return type likely only hides a deeper bug, - // which might be caused by the `param_env` itself. The clauses of the `param_env` - // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, - // see issue #89650 - let cause = traits::ObligationCause::misc(self.span, self.body_id); - let InferOk { value: xform_self_ty, obligations } = - self.fcx.at(&cause, self.param_env).normalize(xform_self_ty); - - debug!( - "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}", - xform_self_ty, xform_ret_ty - ); - self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, - kind: InherentImplCandidate(impl_args, obligations), + kind: InherentImplCandidate(impl_def_id), import_ids: smallvec![], }, true, @@ -810,26 +738,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // a `&self` method will wind up with an argument type like `&dyn Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { - if new_trait_ref.has_non_region_bound_vars() { - this.dcx().span_delayed_bug( - this.span, - "tried to select method from HRTB with non-lifetime bound vars", - ); - return; - } - - let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref); - - let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); this.push_candidate( - Candidate { - xform_self_ty, - xform_ret_ty, - item, - kind: ObjectCandidate, - import_ids: smallvec![], - }, + Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] }, true, ); }); @@ -860,19 +770,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { - let trait_ref = this.instantiate_binder_with_fresh_vars( - this.span, - infer::BoundRegionConversionTime::FnCall, - poly_trait_ref, - ); - - let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args); - this.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, kind: WhereClauseCandidate(poly_trait_ref), import_ids: smallvec![], @@ -929,27 +828,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - fn matches_return_type( - &self, - method: ty::AssocItem, - self_ty: Option>, - expected: Ty<'tcx>, - ) -> bool { + fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool { match method.kind { ty::AssocKind::Fn => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); - - if let Some(self_ty) = self_ty { - if self - .at(&ObligationCause::dummy(), self.param_env) - .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty) - .is_err() - { - return false; - } - } self.can_sub(self.param_env, fty.output(), expected) }), _ => false, @@ -978,21 +862,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { bound_trait_ref.def_id(), )); } else { - let new_trait_ref = self.instantiate_binder_with_fresh_vars( - self.span, - infer::BoundRegionConversionTime::FnCall, - bound_trait_ref, - ); - - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, import_ids: import_ids.clone(), - kind: TraitCandidate(new_trait_ref), + kind: TraitCandidate(bound_trait_ref), }, false, ); @@ -1011,16 +885,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.record_static_candidate(CandidateSource::Trait(trait_def_id)); continue; } - - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, trait_ref.self_ty(), trait_args); self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, import_ids: import_ids.clone(), - kind: TraitCandidate(trait_ref), + kind: TraitCandidate(ty::Binder::dummy(trait_ref)), }, false, ); @@ -1040,7 +909,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .filter(|candidate| candidate_filter(&candidate.item)) .filter(|candidate| { if let Some(return_ty) = self.return_type { - self.matches_return_type(candidate.item, None, return_ty) + self.matches_return_type(candidate.item, return_ty) } else { true } @@ -1450,16 +1319,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource { match candidate.kind { - InherentImplCandidate(..) => { + InherentImplCandidate(_) => { CandidateSource::Impl(candidate.item.container_id(self.tcx)) } - ObjectCandidate | WhereClauseCandidate(_) => { + ObjectCandidate(_) | WhereClauseCandidate(_) => { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } TraitCandidate(trait_ref) => self.probe(|_| { + let trait_ref = + self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref); + let (xform_self_ty, _) = + self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args); let _ = self.at(&ObligationCause::dummy(), self.param_env).sup( DefineOpaqueTypes::No, - candidate.xform_self_ty, + xform_self_ty, self_ty, ); match self.select_trait_candidate(trait_ref) { @@ -1486,54 +1359,46 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) -> ProbeResult { debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); - self.probe(|_| { - // First check that the self type can be related. - let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup( - DefineOpaqueTypes::No, - probe.xform_self_ty, - self_ty, - ) { - Ok(InferOk { obligations, value: () }) => obligations, - Err(err) => { - debug!("--> cannot relate self-types {:?}", err); - return ProbeResult::NoMatch; - } - }; + self.probe(|snapshot| { + let outer_universe = self.universe(); let mut result = ProbeResult::Match; - let mut xform_ret_ty = probe.xform_ret_ty; - debug!(?xform_ret_ty); - - let cause = traits::ObligationCause::misc(self.span, self.body_id); + let cause = &self.misc(self.span); + let ocx = ObligationCtxt::new(self); - let mut parent_pred = None; + let mut trait_predicate = None; + let (mut xform_self_ty, mut xform_ret_ty); - // If so, impls may carry other conditions (e.g., where - // clauses) that must be considered. Make sure that those - // match as well (or at least may match, sometimes we - // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(args, ref ref_obligations) => { - // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, - // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` - // for why this is necessary - let InferOk { - value: normalized_xform_ret_ty, - obligations: normalization_obligations, - } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); - xform_ret_ty = normalized_xform_ret_ty; - debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); - + InherentImplCandidate(impl_def_id) => { + let impl_args = self.fresh_args_for_item(self.span, impl_def_id); + let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, impl_ty, impl_args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + } + // FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates. + xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty); // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container_id(self.tcx); - let impl_bounds = self.tcx.predicates_of(impl_def_id); - let impl_bounds = impl_bounds.instantiate(self.tcx, args); - - let InferOk { value: impl_bounds, obligations: norm_obligations } = - self.fcx.at(&cause, self.param_env).normalize(impl_bounds); - + let impl_bounds = + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); + let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds); // Convert the bounds into obligations. - let impl_obligations = traits::predicates_for_generics( + ocx.register_obligations(traits::predicates_for_generics( |idx, span| { let code = if span.is_dummy() { traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) @@ -1549,106 +1414,92 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }, self.param_env, impl_bounds, - ); - - let candidate_obligations = impl_obligations - .chain(norm_obligations) - .chain(ref_obligations.iter().cloned()) - .chain(normalization_obligations); - - // Evaluate those obligations to see if they might possibly hold. - for o in candidate_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - let parent_o = o.clone(); - let implied_obligations = traits::elaborate(self.tcx, vec![o]); - for o in implied_obligations { - let parent = if o == parent_o { - None - } else { - if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id()) - == self.tcx.lang_items().sized_trait() - { - // We don't care to talk about implicit `Sized` bounds. - continue; - } - Some(parent_o.predicate) - }; - if !self.predicate_may_hold(&o) { - possibly_unsatisfied_predicates.push(( - o.predicate, - parent, - Some(o.cause), - )); - } - } - } - } - } - - ObjectCandidate | WhereClauseCandidate(..) => { - // These have no additional conditions to check. + )); } - - TraitCandidate(trait_ref) => { + TraitCandidate(poly_trait_ref) => { + // Some trait methods are excluded for arrays before 2021. + // (`array.into_iter()` wants a slice iterator for compatibility.) if let Some(method_name) = self.method_name { - // Some trait methods are excluded for arrays before 2021. - // (`array.into_iter()` wants a slice iterator for compatibility.) if self_ty.is_array() && !method_name.span.at_least_rust_2021() { - let trait_def = self.tcx.trait_def(trait_ref.def_id); + let trait_def = self.tcx.trait_def(poly_trait_ref.def_id()); if trait_def.skip_array_during_method_dispatch { return ProbeResult::NoMatch; } } } - let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx); - parent_pred = Some(predicate); - let obligation = - traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate); - if !self.predicate_may_hold(&obligation) { + + let trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + infer::FnCall, + poly_trait_ref, + ); + let trait_ref = ocx.normalize(cause, self.param_env, trait_ref); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + } + let obligation = traits::Obligation::new( + self.tcx, + cause.clone(), + self.param_env, + ty::Binder::dummy(trait_ref), + ); + + // FIXME(-Znext-solver): We only need this hack to deal with fatal + // overflow in the old solver. + if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation) + { + ocx.register_obligation(obligation); + } else { result = ProbeResult::NoMatch; - if self.probe(|_| { - match self.select_trait_candidate(trait_ref) { - Err(_) => return true, - Ok(Some(impl_source)) - if !impl_source.borrow_nested_obligations().is_empty() => - { - for obligation in impl_source.borrow_nested_obligations() { - // Determine exactly which obligation wasn't met, so - // that we can give more context in the error. - if !self.predicate_may_hold(obligation) { - let nested_predicate = - self.resolve_vars_if_possible(obligation.predicate); - let predicate = - self.resolve_vars_if_possible(predicate); - let p = if predicate == nested_predicate { - // Avoid "`MyStruct: Foo` which is required by - // `MyStruct: Foo`" in E0599. - None - } else { - Some(predicate) - }; - possibly_unsatisfied_predicates.push(( - nested_predicate, - p, - Some(obligation.cause.clone()), - )); - } - } - } - _ => { - // Some nested subobligation of this predicate - // failed. - let predicate = self.resolve_vars_if_possible(predicate); - possibly_unsatisfied_predicates.push((predicate, None, None)); + if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) { + for nested_obligation in candidate.nested_obligations() { + if !self.infcx.predicate_may_hold(&nested_obligation) { + possibly_unsatisfied_predicates.push(( + self.resolve_vars_if_possible(nested_obligation.predicate), + Some(self.resolve_vars_if_possible(obligation.predicate)), + Some(nested_obligation.cause), + )); } } - false - }) { - // This candidate's primary obligation doesn't even - // select - don't bother registering anything in - // `potentially_unsatisfied_predicates`. + } + } + + trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx)); + } + ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { + let trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + infer::FnCall, + poly_trait_ref, + ); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; } } @@ -1656,11 +1507,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } // Evaluate those obligations to see if they might possibly hold. - for o in sub_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause))); + for error in ocx.select_where_possible() { + result = ProbeResult::NoMatch; + let nested_predicate = self.resolve_vars_if_possible(error.obligation.predicate); + if let Some(trait_predicate) = trait_predicate + && nested_predicate == self.resolve_vars_if_possible(trait_predicate) + { + // Don't report possibly unsatisfied predicates if the root + // trait obligation from a `TraitCandidate` is unsatisfied. + // That just means the candidate doesn't hold. + } else { + possibly_unsatisfied_predicates.push(( + nested_predicate, + Some(self.resolve_vars_if_possible(error.root_obligation.predicate)) + .filter(|root_predicate| *root_predicate != nested_predicate), + Some(error.obligation.cause), + )); } } @@ -1672,38 +1534,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // We don't normalize the other candidates for perf/backwards-compat reasons... // but `self.return_type` is only set on the diagnostic-path, so we // should be okay doing it here. - if !matches!(probe.kind, InherentImplCandidate(..)) { - let InferOk { - value: normalized_xform_ret_ty, - obligations: normalization_obligations, - } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); - xform_ret_ty = normalized_xform_ret_ty; - debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); - // Evaluate those obligations to see if they might possibly hold. - for o in normalization_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push(( - o.predicate, - None, - Some(o.cause), - )); - } - } + if !matches!(probe.kind, InherentImplCandidate(_)) { + xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty); } debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty); - if let ProbeResult::Match = result - && self - .at(&ObligationCause::dummy(), self.param_env) - .sup(DefineOpaqueTypes::Yes, return_ty, xform_ret_ty) - .is_err() - { - result = ProbeResult::BadReturnType; + match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) { + Ok(()) => {} + Err(_) => { + result = ProbeResult::BadReturnType; + } + } + + // Evaluate those obligations to see if they might possibly hold. + for error in ocx.select_where_possible() { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push(( + error.obligation.predicate, + Some(error.root_obligation.predicate) + .filter(|predicate| *predicate != error.obligation.predicate), + Some(error.root_obligation.cause), + )); } } + // Previously, method probe used `evaluate_predicate` to determine if a predicate + // was impossible to satisfy. This did a leak check, so we must also do a leak + // check here to prevent backwards-incompatible ambiguity being introduced. See + // `tests/ui/methods/leak-check-disquality.rs` for a simple example of when this + // may happen. + if let Err(_) = self.leak_check(outer_universe, Some(snapshot)) { + result = ProbeResult::NoMatch; + } + result }) } @@ -1894,40 +1757,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn_sig.instantiate(self.tcx, args) }; - self.instantiate_bound_regions_with_erased(xform_fn_sig) - } - - /// Gets the type of an impl and generate generic parameters with inference vars. - fn impl_ty_and_args( - &self, - impl_def_id: DefId, - ) -> (ty::EarlyBinder>, GenericArgsRef<'tcx>) { - (self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id)) - } - - /// Replaces late-bound-regions bound by `value` with `'static` using - /// `ty::instantiate_bound_regions_with_erased`. - /// - /// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of - /// method matching. It is reasonable during the probe phase because we don't consider region - /// relationships at all. Therefore, we can just replace all the region variables with 'static - /// rather than creating fresh region variables. This is nice for two reasons: - /// - /// 1. Because the numbers of the region variables would otherwise be fairly unique to this - /// particular method call, it winds up creating fewer types overall, which helps for memory - /// usage. (Admittedly, this is a rather small effect, though measurable.) - /// - /// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any - /// late-bound regions with 'static. Otherwise, if we were going to replace late-bound - /// regions with actual region variables as is proper, we'd have to ensure that the same - /// region got replaced with the same variable, which requires a bit more coordination - /// and/or tracking the instantiations and - /// so forth. - fn instantiate_bound_regions_with_erased(&self, value: ty::Binder<'tcx, T>) -> T - where - T: TypeFoldable>, - { - self.tcx.instantiate_bound_regions_with_erased(value) + self.tcx.instantiate_bound_regions_with_erased(xform_fn_sig) } /// Determine if the given associated item type is relevant in the current context. @@ -2051,10 +1881,10 @@ impl<'tcx> Candidate<'tcx> { Pick { item: self.item, kind: match self.kind { - InherentImplCandidate(..) => InherentImplPick, - ObjectCandidate => ObjectPick, + InherentImplCandidate(_) => InherentImplPick, + ObjectCandidate(_) => ObjectPick, TraitCandidate(_) => TraitPick, - WhereClauseCandidate(ref trait_ref) => { + WhereClauseCandidate(trait_ref) => { // Only trait derived from where-clauses should // appear here, so they should not contain any // inference variables or other artifacts. This @@ -2065,7 +1895,7 @@ impl<'tcx> Candidate<'tcx> { && !trait_ref.skip_binder().args.has_placeholders() ); - WhereClausePick(*trait_ref) + WhereClausePick(trait_ref) } }, import_ids: self.import_ids.clone(), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 46227e406a328..078009515e428 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -125,11 +125,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(arg_ty) = args[0].as_type() else { return false; }; - let ty::Param(param) = arg_ty.kind() else { + let ty::Param(param) = *arg_ty.kind() else { return false; }; // Is `generic_param` the same as the arg for this trait predicate? - generic_param.index == generics.type_param(¶m, tcx).index + generic_param.index == generics.type_param(param, tcx).index } else { false } @@ -156,10 +156,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - match ty.peel_refs().kind() { + match *ty.peel_refs().kind() { ty::Param(param) => { let generics = self.tcx.generics_of(self.body_id); - let generic_param = generics.type_param(¶m, self.tcx); + let generic_param = generics.type_param(param, self.tcx); for unsatisfied in unsatisfied_predicates.iter() { // The parameter implements `IntoIterator` // but it has called a method that requires it to implement `Iterator` @@ -3232,9 +3232,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .sort_by_key(|&info| (!info.def_id.is_local(), self.tcx.def_path_str(info.def_id))); candidates.dedup(); - let param_type = match rcvr_ty.kind() { + let param_type = match *rcvr_ty.kind() { ty::Param(param) => Some(param), - ty::Ref(_, ty, _) => match ty.kind() { + ty::Ref(_, ty, _) => match *ty.kind() { ty::Param(param) => Some(param), _ => None, }, @@ -3291,14 +3291,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param.name.ident(), )); let bounds_span = hir_generics.bounds_span_for_suggestions(def_id); - if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() { + if rcvr_ty.is_ref() + && param.is_impl_trait() + && let Some((bounds_span, _)) = bounds_span + { err.multipart_suggestions( msg, candidates.iter().map(|t| { vec![ (param.span.shrink_to_lo(), "(".to_string()), ( - bounds_span.unwrap(), + bounds_span, format!(" + {})", self.tcx.def_path_str(t.def_id)), ), ] @@ -3308,32 +3311,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let (sp, introducer) = if let Some(span) = bounds_span { - (span, Introducer::Plus) - } else if let Some(colon_span) = param.colon_span { - (colon_span.shrink_to_hi(), Introducer::Nothing) - } else if param.is_impl_trait() { - (param.span.shrink_to_hi(), Introducer::Plus) - } else { - (param.span.shrink_to_hi(), Introducer::Colon) - }; + let (sp, introducer, open_paren_sp) = + if let Some((span, open_paren_sp)) = bounds_span { + (span, Introducer::Plus, open_paren_sp) + } else if let Some(colon_span) = param.colon_span { + (colon_span.shrink_to_hi(), Introducer::Nothing, None) + } else if param.is_impl_trait() { + (param.span.shrink_to_hi(), Introducer::Plus, None) + } else { + (param.span.shrink_to_hi(), Introducer::Colon, None) + }; - err.span_suggestions( - sp, + let all_suggs = candidates.iter().map(|cand| { + let suggestion = format!( + "{} {}", + match introducer { + Introducer::Plus => " +", + Introducer::Colon => ":", + Introducer::Nothing => "", + }, + self.tcx.def_path_str(cand.def_id) + ); + + let mut suggs = vec![]; + + if let Some(open_paren_sp) = open_paren_sp { + suggs.push((open_paren_sp, "(".to_string())); + suggs.push((sp, format!("){suggestion}"))); + } else { + suggs.push((sp, suggestion)); + } + + suggs + }); + + err.multipart_suggestions( msg, - candidates.iter().map(|t| { - format!( - "{} {}", - match introducer { - Introducer::Plus => " +", - Introducer::Colon => ":", - Introducer::Nothing => "", - }, - self.tcx.def_path_str(t.def_id) - ) - }), + all_suggs, Applicability::MaybeIncorrect, ); + return; } Node::Item(hir::Item { @@ -3429,7 +3446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { param_type.map_or_else( || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. - ToString::to_string, + |p| p.to_string(), ) }, }, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 49d0c8bfcd1b8..a4f840d849dd2 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op); - Ty::new_unit(self.tcx) + self.tcx.types.unit } else { return_ty }; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 6040b689f49d4..382dba5f95fb9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1228,16 +1228,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else { - // Pattern has wrong number of fields. - let e = - self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err); + let e = self.emit_err_pat_wrong_number_of_fields( + pat.span, + res, + qpath, + subpats, + &variant.fields.raw, + expected, + had_err, + ); on_error(e); return Ty::new_error(tcx, e); } pat_ty } - fn e0023( + fn emit_err_pat_wrong_number_of_fields( &self, pat_span: Span, res: Res, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 875f8b23a84b8..0a40ffb0d5aab 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -551,15 +551,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_coroutine_interior(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - self.tcx().with_stable_hashing_context(move |ref hcx| { - for (&expr_def_id, predicates) in - fcx_typeck_results.coroutine_interior_predicates.to_sorted(hcx, false).into_iter() - { - let predicates = - self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id)); - self.typeck_results.coroutine_interior_predicates.insert(expr_def_id, predicates); - } - }) + for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates { + let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span); + self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause)); + } } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index aa6f184a2d7d1..8c66f239f8ee9 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -46,6 +46,7 @@ use rustc_middle::dep_graph::{ }; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 0729986f32fdf..79402c88de47a 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -6,8 +6,6 @@ #![feature(rustdoc_internals)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_middle; #[macro_use] extern crate tracing; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index bf6ee044a0bd2..3d7c0cfc30aa3 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -110,6 +110,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; +use rustc_middle::bug; use rustc_session::config::CrateType; use rustc_session::output::{collect_crate_types, find_crate_name}; use rustc_session::{Session, StableCrateId}; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 4593108edac03..2acaeac24398d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -239,7 +239,7 @@ impl Subdiagnostic for RegionOriginNote<'_> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut label_or_note = |span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); @@ -304,7 +304,7 @@ impl Subdiagnostic for LifetimeMismatchLabels { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { @@ -352,7 +352,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut mk_suggestion = || { let ( @@ -454,7 +454,7 @@ impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { fn add_to_diag_with>( mut self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { self.unmet_requirements .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); @@ -773,7 +773,7 @@ impl Subdiagnostic for ConsiderBorrowingParamHelp { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { @@ -818,7 +818,7 @@ impl Subdiagnostic for DynTraitConstraintSuggestion { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); @@ -865,7 +865,7 @@ impl Subdiagnostic for ReqIntroducedLocations { fn add_to_diag_with>( mut self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer_ril_introduced_here); @@ -888,7 +888,7 @@ impl Subdiagnostic for MoreTargeted { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); @@ -1293,7 +1293,7 @@ impl Subdiagnostic for SuggestTuplePatternMany { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 7b962b0140808..70d94873530e7 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -163,7 +163,7 @@ impl Subdiagnostic for RegionExplanation<'_> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index c8adbf7f57ab4..f95cc13623cd1 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -7,6 +7,7 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_macros::extension; use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fdae9d84b5ff6..635bbca37ecc2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -68,6 +68,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; +use rustc_macros::extension; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; @@ -2369,9 +2370,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { generic_param_scope = self.tcx.local_parent(generic_param_scope); } - // type_param_sugg_span is (span, has_bounds) + // type_param_sugg_span is (span, has_bounds, needs_parentheses) let (type_scope, type_param_sugg_span) = match bound_kind { - GenericKind::Param(ref param) => { + GenericKind::Param(param) => { let generics = self.tcx.generics_of(generic_param_scope); let def_id = generics.type_param(param, self.tcx).def_id.expect_local(); let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id; @@ -2380,10 +2381,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // instead we suggest `T: 'a + 'b` in that case. let hir_generics = self.tcx.hir().get_generics(scope).unwrap(); let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) { - Some(span) => Some((span, true)), + Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)), // If `param` corresponds to `Self`, no usable suggestion span. None if generics.has_self && param.index == 0 => None, - None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)), + None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)), }; (scope, sugg_span) } @@ -2406,12 +2407,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut suggs = vec![]; let lt_name = self.suggest_name_region(sub, &mut suggs); - if let Some((sp, has_lifetimes)) = type_param_sugg_span + if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span && suggestion_scope == type_scope { let suggestion = if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") }; - suggs.push((sp, suggestion)) + + if let Some(open_paren_sp) = open_paren_sp { + suggs.push((open_paren_sp, "(".to_string())); + suggs.push((sp, format!("){suggestion}"))); + } else { + suggs.push((sp, suggestion)) + } } else if let GenericKind::Alias(ref p) = bound_kind && let ty::Projection = p.kind(self.tcx) && let DefKind::AssocTy = self.tcx.def_kind(p.def_id) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 008b75b4c9a18..6a42f9b42c384 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -28,7 +28,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match err { ArgumentSorts(values, _) | Sorts(values) => { - match (values.expected.kind(), values.found.kind()) { + match (*values.expected.kind(), *values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { diag.note("no two closures, even if identical, have the same type"); diag.help("consider boxing your closure and/or using it as a trait object"); @@ -452,7 +452,7 @@ impl Trait for X { } (ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => { - if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() { + if tcx.fn_sig(def_id).skip_binder().unsafety() < sig.unsafety() { diag.note( "unsafe functions cannot be coerced into safe function pointers", ); @@ -527,7 +527,7 @@ impl Trait for X { diag: &mut Diag<'_>, msg: impl Fn() -> String, body_owner_def_id: DefId, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; @@ -541,7 +541,7 @@ impl Trait for X { }; // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. - let ty::Param(param_ty) = proj_ty.self_ty().kind() else { + let ty::Param(param_ty) = *proj_ty.self_ty().kind() else { return false; }; let generics = tcx.generics_of(body_owner_def_id); @@ -598,7 +598,7 @@ impl Trait for X { fn expected_projection( &self, diag: &mut Diag<'_>, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, values: ExpectedFound>, body_owner_def_id: DefId, cause_code: &ObligationCauseCode<'_>, @@ -709,7 +709,7 @@ fn foo(&self) -> Self::T { String::new() } &self, diag: &mut Diag<'_>, msg: impl Fn() -> String, - proj_ty: &ty::AliasTy<'tcx>, + proj_ty: ty::AliasTy<'tcx>, ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 81130d691510c..bb53aec0b4d13 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,6 +4,7 @@ pub use lexical_region_resolve::RegionResolutionError; pub use relate::combine::CombineFields; pub use relate::combine::ObligationEmittingRelation; pub use relate::StructurallyRelateAliases; +pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; @@ -20,13 +21,13 @@ use opaque_types::OpaqueTypeStorage; use region_constraints::{GenericKind, VarInfos, VerifyBound}; use region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::EffectVarValue; @@ -478,7 +479,7 @@ pub enum SubregionOrigin<'tcx> { // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -static_assert_size!(SubregionOrigin<'_>, 32); +rustc_data_structures::static_assert_size!(SubregionOrigin<'_>, 32); impl<'tcx> SubregionOrigin<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 3d6b54721d039..223e6e3d34416 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -11,6 +11,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; use rustc_index::IndexVec; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey}; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index a5f52420a84b0..0299af61d45ca 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -18,7 +18,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extend_one)] @@ -30,11 +29,6 @@ #![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc -#[macro_use] -extern crate rustc_macros; -#[cfg(target_pointer_width = "64")] -#[macro_use] -extern crate rustc_data_structures; #[macro_use] extern crate tracing; #[macro_use] diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index c495810858f7f..cb067c7a6600d 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,6 +1,7 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_hir::def_id::DefId; +use rustc_macros::extension; use rustc_middle::ty::{self, ToPredicate, Ty}; use super::FulfillmentError; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 7b4e085293c43..e3611ab28e532 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -113,7 +113,7 @@ impl<'tcx> PolyTraitObligation<'tcx> { // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -static_assert_size!(PredicateObligation<'_>, 48); +rustc_data_structures::static_assert_size!(PredicateObligation<'_>, 48); pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index d0ce23dacb5ef..75df006a56f11 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,4 @@ #![feature(decl_macro)] -#![feature(generic_nonzero)] #![feature(lazy_cell)] #![feature(let_chains)] #![feature(thread_spawn_unchecked)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 91cef02c7d17d..b593c41a8eafa 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -759,7 +759,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|def_id| { if tcx.is_coroutine(def_id.to_def_id()) { tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations(def_id); + tcx.ensure().check_coroutine_obligations( + tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), + ); } }); sess.time("layout_testing", || layout_test::test_layout(tcx)); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index ee677a092e2f1..1b9165342d45d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal}; -use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; use rustc_metadata::creader::CStore; @@ -140,11 +140,16 @@ impl<'tcx> Queries<'tcx> { let cstore = FreezeLock::new(Box::new(CStore::new( self.compiler.codegen_backend.metadata_loader(), - stable_crate_id, )) as _); let definitions = FreezeLock::new(Definitions::new(stable_crate_id)); - let untracked = - Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions }; + + let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default()); + let untracked = Untracked { + cstore, + source_span: AppendOnlyIndexVec::new(), + definitions, + stable_crate_ids, + }; let qcx = passes::create_global_ctxt( self.compiler, @@ -158,7 +163,8 @@ impl<'tcx> Queries<'tcx> { ); qcx.enter(|tcx| { - let feed = tcx.feed_local_crate(); + let feed = tcx.create_crate_num(stable_crate_id).unwrap(); + assert_eq!(feed.key(), LOCAL_CRATE); feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8d741ef4c1b69..db150cc1f875d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -4,12 +4,12 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, - CollapseMacroDebuginfo, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, - ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, - InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, - NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, - Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, - WasiExecModel, + CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, + ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, + Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, + LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, + PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, + SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -321,6 +321,7 @@ fn test_search_paths_tracking_hash_different_order() { &opts.target_triple, &early_dcx, search_path, + false, )); }; @@ -599,6 +600,7 @@ fn test_codegen_options_tracking_hash() { // Make sure that changing a [TRACKED] option changes the hash. // tidy-alphabetical-start tracked!(code_model, Some(CodeModel::Large)); + tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); @@ -759,12 +761,10 @@ fn test_unstable_options_tracking_hash() { }) ); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); - tracked!(coverage_options, CoverageOptions { branch: true, mcdc: true }); + tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc }); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); - tracked!(debug_macros, true); tracked!(default_hidden_visibility, Some(true)); tracked!(dep_info_omit_d_target, true); tracked!(direct_access_external_data, Some(true)); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 83fff98bad56c..6f8a9792b6ce8 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -630,7 +630,7 @@ impl Cursor<'_> { // with a number self.bump(); let mut empty_exponent = false; - if self.first().is_digit(10) { + if self.first().is_ascii_digit() { self.eat_decimal_digits(); match self.first() { 'e' | 'E' => { @@ -661,7 +661,7 @@ impl Cursor<'_> { // If the first symbol is valid for identifier, it can be a lifetime. // Also check if it's a number for a better error reporting (so '0 will // be reported as invalid lifetime and not as unterminated char literal). - is_id_start(self.first()) || self.first().is_digit(10) + is_id_start(self.first()) || self.first().is_ascii_digit() }; if !can_be_a_lifetime { @@ -677,7 +677,7 @@ impl Cursor<'_> { // Either a lifetime or a character literal with // length greater than 1. - let starts_with_number = self.first().is_digit(10); + let starts_with_number = self.first().is_ascii_digit(); // Skip the literal contents. // First symbol can be a number (which isn't a valid identifier start), diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 03d178eb266a4..d6ea4249247f3 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -259,7 +259,7 @@ fn scan_escape + From>( } else { // This may be a high byte, but that will only happen if `T` is // `MixedUnit`, because of the `allow_high_bytes` check above. - Ok(T::from(value as u8)) + Ok(T::from(value)) }; } 'u' => return scan_unicode(chars, mode.allow_unicode_escapes()).map(T::from), @@ -300,7 +300,7 @@ fn scan_unicode(chars: &mut Chars<'_>, allow_unicode_escapes: bool) -> Result 0x10FFFF { EscapeError::OutOfRangeUnicodeEscape } else { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 82b90e1660a95..676a7c21841a1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -456,6 +456,8 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, th [one] `{$body_name}` *[other] `{$body_name}` and up {$depth} bodies } + .help_doctest = + remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` .non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 3a5c585366a31..8f4bae339573c 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -3,9 +3,11 @@ use crate::{ LateContext, LateLintPass, LintContext, }; use rustc_hir as hir; +use rustc_middle::bug; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 5f7a3137d52d4..40778542c75c9 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -2,6 +2,7 @@ use crate::lints::AsyncFnInTraitDiag; use crate::LateContext; use crate::LateLintPass; use rustc_hir as hir; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait; declare_lint! { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8b974a461d4da..ba316e5eeb041 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,6 +51,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}; +use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -59,6 +60,7 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason}; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1769,13 +1771,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } declare_lint! { - /// The `keyword_idents` lint detects edition keywords being used as an + /// The `keyword_idents_2018` lint detects edition keywords being used as an /// identifier. /// /// ### Example /// /// ```rust,edition2015,compile_fail - /// #![deny(keyword_idents)] + /// #![deny(keyword_idents_2018)] /// // edition 2015 /// fn dyn() {} /// ``` @@ -1804,7 +1806,7 @@ declare_lint! { /// [editions]: https://doc.rust-lang.org/edition-guide/ /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html - pub KEYWORD_IDENTS, + pub KEYWORD_IDENTS_2018, Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { @@ -1813,9 +1815,54 @@ declare_lint! { }; } +declare_lint! { + /// The `keyword_idents_2024` lint detects edition keywords being used as an + /// identifier. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(keyword_idents_2024)] + /// // edition 2015 + /// fn gen() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses new keywords + /// that are added to the language that are used as identifiers (such as a + /// variable name, function name, etc.). If you switch the compiler to a + /// new edition without updating the code, then it will fail to compile if + /// you are using a new keyword as an identifier. + /// + /// You can manually change the identifiers to a non-keyword, or use a + /// [raw identifier], for example `r#gen`, to transition to a new edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler (which is + /// to use a raw identifier). This provides a completely automated way to + /// update old code for a new edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html + pub KEYWORD_IDENTS_2024, + Allow, + "detects edition keywords being used as an identifier", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #49716 ", + }; +} + declare_lint_pass!( /// Check for uses of edition keywords used as an identifier. - KeywordIdents => [KEYWORD_IDENTS] + KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024] ); struct UnderMacro(bool); @@ -1841,42 +1888,39 @@ impl KeywordIdents { UnderMacro(under_macro): UnderMacro, ident: Ident, ) { - let next_edition = match cx.sess().edition() { - Edition::Edition2015 => { - match ident.name { - kw::Async | kw::Await | kw::Try => Edition::Edition2018, - - // rust-lang/rust#56327: Conservatively do not - // attempt to report occurrences of `dyn` within - // macro definitions or invocations, because `dyn` - // can legitimately occur as a contextual keyword - // in 2015 code denoting its 2018 meaning, and we - // do not want rustfix to inject bugs into working - // code by rewriting such occurrences. - // - // But if we see `dyn` outside of a macro, we know - // its precise role in the parsed AST and thus are - // assured this is truly an attempt to use it as - // an identifier. - kw::Dyn if !under_macro => Edition::Edition2018, - - _ => return, - } - } + let (lint, edition) = match ident.name { + kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018), + + // rust-lang/rust#56327: Conservatively do not + // attempt to report occurrences of `dyn` within + // macro definitions or invocations, because `dyn` + // can legitimately occur as a contextual keyword + // in 2015 code denoting its 2018 meaning, and we + // do not want rustfix to inject bugs into working + // code by rewriting such occurrences. + // + // But if we see `dyn` outside of a macro, we know + // its precise role in the parsed AST and thus are + // assured this is truly an attempt to use it as + // an identifier. + kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018), + + kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024), - // There are no new keywords yet for the 2018 edition and beyond. _ => return, }; // Don't lint `r#foo`. - if cx.sess().psess.raw_identifier_spans.contains(ident.span) { + if ident.span.edition() >= edition + || cx.sess().psess.raw_identifier_spans.contains(ident.span) + { return; } cx.emit_span_lint( - KEYWORD_IDENTS, + lint, ident.span, - BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span }, + BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span }, ); } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 64ef30039a80e..0931bb29963de 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -27,6 +27,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError}; @@ -110,7 +111,7 @@ struct LintAlias { struct LintGroup { lint_ids: Vec, - is_loaded: bool, + is_externally_loaded: bool, depr: Option, } @@ -159,7 +160,9 @@ impl LintStore { // Don't display deprecated lint groups. depr.is_none() }) - .map(|(k, LintGroup { lint_ids, is_loaded, .. })| (*k, lint_ids.clone(), *is_loaded)) + .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| { + (*k, lint_ids.clone(), *is_externally_loaded) + }) } pub fn register_early_pass( @@ -218,7 +221,7 @@ impl LintStore { .entry(edition.lint_name()) .or_insert(LintGroup { lint_ids: vec![], - is_loaded: lint.is_loaded, + is_externally_loaded: lint.is_externally_loaded, depr: None, }) .lint_ids @@ -231,7 +234,7 @@ impl LintStore { .entry("future_incompatible") .or_insert(LintGroup { lint_ids: vec![], - is_loaded: lint.is_loaded, + is_externally_loaded: lint.is_externally_loaded, depr: None, }) .lint_ids @@ -246,7 +249,7 @@ impl LintStore { alias, LintGroup { lint_ids: vec![], - is_loaded: false, + is_externally_loaded: false, depr: Some(LintAlias { name: lint_name, silent: true }), }, ); @@ -254,21 +257,21 @@ impl LintStore { pub fn register_group( &mut self, - is_loaded: bool, + is_externally_loaded: bool, name: &'static str, deprecated_name: Option<&'static str>, to: Vec, ) { let new = self .lint_groups - .insert(name, LintGroup { lint_ids: to, is_loaded, depr: None }) + .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None }) .is_none(); if let Some(deprecated) = deprecated_name { self.lint_groups.insert( deprecated, LintGroup { lint_ids: vec![], - is_loaded, + is_externally_loaded, depr: Some(LintAlias { name, silent: false }), }, ); @@ -741,7 +744,7 @@ impl<'tcx> LateContext<'tcx> { .filter(|typeck_results| typeck_results.hir_owner == id.owner) .or_else(|| { self.tcx - .has_typeck_results(id.owner.to_def_id()) + .has_typeck_results(id.owner.def_id) .then(|| self.tcx.typeck(id.owner.def_id)) }) .and_then(|typeck_results| typeck_results.type_dependent_def(id)) diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index b2403836397a1..8458b53933537 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -2,7 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::{add_elided_lifetime_in_path_suggestion, Diag}; +use rustc_errors::{elided_lifetime_in_path_suggestion, Diag}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_middle::middle::stability; use rustc_session::lint::BuiltinLintDiag; @@ -74,13 +74,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di diag.span_note(span_def, "the macro is defined here"); } BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - add_elided_lifetime_in_path_suggestion( - sess.source_map(), - diag, - n, - path_span, - incl_angl_brckt, - insertion_span, + diag.subdiagnostic( + sess.dcx(), + elided_lifetime_in_path_suggestion( + sess.source_map(), + n, + path_span, + incl_angl_brckt, + insertion_span, + ), ); } BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => { diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs index 0472525d49a44..e9a6276192e52 100644 --- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -1,4 +1,5 @@ use rustc_errors::{Applicability, Diag}; +use rustc_middle::bug; use rustc_session::{config::ExpectedValues, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{sym, Span, Symbol}; diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 9bc81d2c46aa1..b671dfaa0d1b0 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -6,6 +6,7 @@ use crate::{ use rustc_hir as hir; use rustc_middle::ty; use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; use rustc_trait_selection::traits::supertraits; diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 78ac7f9b2354d..60b799f3c7468 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -1,5 +1,6 @@ use rustc_hir::{Arm, Expr, ExprKind, Node}; use rustc_middle::ty; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; use crate::{ diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 9fae32a49c782..3f627baf7704f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -99,7 +99,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { self.with_lint_attrs(it.id, &it.attrs, |cx| { - ast_visit::walk_foreign_item(cx, it); + ast_visit::walk_item(cx, it); }) } diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index a67f1b62fb0d6..958da177eda5d 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -5,6 +5,7 @@ use crate::{ }; use rustc_hir as hir; use rustc_middle::ty::{visit::TypeVisitableExt, Ty}; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::sym, Span}; declare_lint! { diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index ee99e824a548b..c23d1221bc866 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -27,7 +27,7 @@ impl Subdiagnostic for OverruledAttributeSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { OverruledAttributeSub::DefaultSource { id } => { diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index cb7feea16b538..ce3f45a17e9f6 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -10,6 +10,7 @@ use hir::{Expr, Pat}; use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_middle::ty::{self, List}; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::ObligationCtxt; diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index fae492f252e5f..48e5683fc0a9b 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -5,6 +5,7 @@ use rustc_hir::def::DefKind; use rustc_middle::query::Providers; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_session::declare_lint; use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::FIRST_VARIANT; diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 054cfe92a3a48..aa8ca1776dc03 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -7,6 +7,7 @@ use crate::{ }; use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use rustc_ast as ast; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{BytePos, Span, Symbol}; declare_lint! { diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 081e3e875302b..0081374922e6c 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -2,6 +2,7 @@ use std::str::Utf8Error; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 9d4d75a646aee..ea82fb9f26252 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -5,6 +5,7 @@ use crate::{ use rustc_errors::MultiSpan; use rustc_hir as hir; use rustc_middle::ty; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{sym, Symbol}; declare_lint! { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 5bb2942ad4b75..12b3d1d2f9e4f 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -22,6 +22,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; use rustc_index::IndexVec; +use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ lint_level, reveal_actual_level, LevelAndSource, LintExpectation, LintLevelSource, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 31c80c4d75bb1..a78b410f500c1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,7 +32,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extract_if)] -#![feature(generic_nonzero)] #![feature(if_let_guard)] #![feature(iter_order_by)] #![feature(let_chains)] @@ -40,10 +39,6 @@ #![feature(rustc_attrs)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_middle; -#[macro_use] -extern crate rustc_session; #[macro_use] extern crate tracing; @@ -313,6 +308,8 @@ fn register_builtins(store: &mut LintStore) { // MACRO_USE_EXTERN_CRATE ); + add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024); + add_lint_group!( "refining_impl_trait", REFINING_IMPL_TRAIT_REACHABLE, @@ -325,7 +322,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("bare_trait_object", "bare_trait_objects"); store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); - store.register_renamed("async_idents", "keyword_idents"); + store.register_renamed("async_idents", "keyword_idents_2018"); store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a034bebc85ec0..7efa5245baa20 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -274,7 +274,7 @@ impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { // Access to associates types should use `::Assoc`, which does not need a // bound. Let's see if this type does that. @@ -330,7 +330,7 @@ impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.multipart_suggestion( fluent::lint_suggestion, @@ -451,7 +451,7 @@ impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut err = self.err; loop { @@ -506,7 +506,7 @@ impl Subdiagnostic for BuiltinClashingExternSub<'_> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); @@ -788,7 +788,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); @@ -806,7 +806,7 @@ impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { @@ -954,7 +954,7 @@ impl Subdiagnostic for NonBindingLetSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; @@ -1240,7 +1240,7 @@ impl Subdiagnostic for NonSnakeCaseDiagSub { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { NonSnakeCaseDiagSub::Label { span } => { @@ -1350,14 +1350,18 @@ pub enum NonLocalDefinitionsDiag { const_anon: Option, }, #[diag(lint_non_local_definitions_macro_rules)] - #[help] - #[note(lint_non_local)] - #[note(lint_exception)] - #[note(lint_non_local_definitions_deprecation)] MacroRules { depth: u32, body_kind_descr: &'static str, body_name: String, + #[help] + help: Option<()>, + #[help(lint_help_doctest)] + doctest_help: Option<()>, + #[note(lint_non_local)] + #[note(lint_exception)] + #[note(lint_non_local_definitions_deprecation)] + notes: (), #[subdiagnostic] cargo_update: Option, }, @@ -1482,7 +1486,7 @@ impl Subdiagnostic for OverflowingBinHexSign { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { OverflowingBinHexSign::Positive => { diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 07980cfb6fa0f..e355604e2068c 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -6,6 +6,7 @@ use rustc_middle::{ query::Key, ty::{self, Ty}, }; +use rustc_session::{declare_lint, declare_lint_pass}; declare_lint! { /// The `map_unit_fn` lint checks for `Iterator::map` receive diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 9cfdaf0ce2ff6..b93245d58d9d8 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -4,6 +4,7 @@ use crate::LateLintPass; use crate::LintContext; use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::sym, Span}; declare_lint! { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 69d623b547b58..48d140c6b7f36 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -1,6 +1,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_hir as hir; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; declare_lint! { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 79bc78ae55a8d..9f298a6071c69 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -6,6 +6,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordMap; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::symbol::Symbol; use unicode_security::general_security_profile::IdentifierType; diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index a2d07fff5067c..a6057afcbd6b5 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -4,10 +4,12 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_parse_format::{ParseMode, Parser, Piece}; use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::{hygiene, sym, symbol::kw, InnerSpan, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; @@ -53,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { if Some(def_id) == cx.tcx.lang_items().begin_panic_fn() || Some(def_id) == cx.tcx.lang_items().panic_fn() - || f_diagnostic_name == Some(sym::panic_str) + || f_diagnostic_name == Some(sym::panic_str_2015) { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { if matches!( diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 004c2c2e4f44f..7bdf5ef6af406 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -5,6 +5,7 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable}; +use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::Span; use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind}; @@ -232,6 +233,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { ItemKind::Macro(_macro, MacroKind::Bang) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => { + // determining we if are in a doctest context can't currently be determined + // by the code it-self (no specific attrs), but fortunatly rustdoc sets a + // perma-unstable env for libtest so we just re-use that env for now + let is_at_toplevel_doctest = + self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok(); + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, item.span, @@ -242,6 +249,9 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { .map(|s| s.to_ident_string()) .unwrap_or_else(|| "".to_string()), cargo_update: cargo_update(), + help: (!is_at_toplevel_doctest).then_some(()), + doctest_help: is_at_toplevel_doctest.then_some(()), + notes: (), }, ) } @@ -356,7 +366,7 @@ fn path_has_local_parent( } /// Given a def id and a parent impl def id, this checks if the parent -/// def id correspond to the def id of the parent impl definition. +/// def id (modulo modules) correspond to the def id of the parent impl definition. #[inline] fn did_has_local_parent( did: DefId, @@ -364,8 +374,14 @@ fn did_has_local_parent( impl_parent: DefId, impl_parent_parent: Option, ) -> bool { - did.is_local() && { - let res_parent = tcx.parent(did); - res_parent == impl_parent || Some(res_parent) == impl_parent_parent - } + did.is_local() + && if let Some(did_parent) = tcx.opt_parent(did) { + did_parent == impl_parent + || Some(did_parent) == impl_parent_parent + || !did_parent.is_crate_root() + && tcx.def_kind(did_parent) == DefKind::Mod + && did_has_local_parent(did_parent, tcx, impl_parent, impl_parent_parent) + } else { + false + } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index ee863672017d5..dbb0644cd63f6 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -11,6 +11,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{GenericParamKind, PatKind}; use rustc_middle::ty; use rustc_session::config::CrateType; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::{BytePos, Span}; diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 970d411fb0657..91441248e70fd 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -8,6 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::symbol::sym; declare_lint! { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index ec7954536bec4..1ea1f496e508e 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -4,6 +4,7 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable, }; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::kw, Span}; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 160d42caa9e2a..1f0a8a0b56783 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_tool_lint! { diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 1681ac2f1e5a4..ef08e79e24a0a 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -1,5 +1,6 @@ use crate::{lints::RedundantSemicolonsDiag, EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::{Block, StmtKind}; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::Span; declare_lint! { diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 9b938b34c00a7..9fed91f72628e 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -2,6 +2,7 @@ use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, layout::TyAndLayout}; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext}; diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 789f154eac5bc..4d1b1dc4fb783 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -3,6 +3,7 @@ use crate::LateContext; use crate::LateLintPass; use crate::LintContext; use rustc_hir as hir; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::symbol::sym; declare_lint! { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index e982842f5363f..13b6054586cd5 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -17,11 +17,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir as hir; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; +use rustc_middle::bug; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{ self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map; use rustc_span::symbol::sym; diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs index 6222adf58ae70..8202bfa805a29 100644 --- a/compiler/rustc_lint/src/unit_bindings.rs +++ b/compiler/rustc_lint/src/unit_bindings.rs @@ -1,7 +1,7 @@ use crate::lints::UnitBindingsDiag; use crate::{LateLintPass, LintContext}; use rustc_hir as hir; -use rustc_middle::ty::Ty; +use rustc_session::{declare_lint, declare_lint_pass}; declare_lint! { /// The `unit_bindings` lint detects cases where bindings are useless because they have @@ -56,8 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for UnitBindings { && let Some(init) = local.init && let init_ty = tyck_results.expr_ty(init) && let local_ty = tyck_results.node_type(local.hir_id) - && init_ty == Ty::new_unit(cx.tcx) - && local_ty == Ty::new_unit(cx.tcx) + && init_ty == cx.tcx.types.unit + && local_ty == cx.tcx.types.unit && local.ty.is_none() && !matches!(init.kind, hir::ExprKind::Tup([])) && !matches!(local.pat.kind, hir::PatKind::Tuple([], ..)) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0b0949e4dd861..4d372d612e90d 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; @@ -176,6 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { | hir::BinOpKind::Shr => Some("bitwise operation"), }, hir::ExprKind::AddrOf(..) => Some("borrow"), + hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"), hir::ExprKind::Unary(..) => Some("unary operation"), _ => None, }; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e74cc388cab4c..c7996c27c2f09 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -69,6 +69,7 @@ declare_lint_pass! { MISSING_FRAGMENT_SPECIFIER, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, + NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, ORDER_DEPENDENT_TRAIT_OBJECTS, @@ -101,6 +102,7 @@ declare_lint_pass! { TYVAR_BEHIND_RAW_POINTER, UNCONDITIONAL_PANIC, UNCONDITIONAL_RECURSION, + UNCOVERED_PARAM_IN_PROJECTION, UNDEFINED_NAKED_FUNCTION_ABI, UNEXPECTED_CFGS, UNFULFILLED_LINT_EXPECTATIONS, @@ -4244,6 +4246,85 @@ declare_lint! { "named arguments in format used positionally" } +declare_lint! { + /// The `never_type_fallback_flowing_into_unsafe` lint detects cases where never type fallback + /// affects unsafe function calls. + /// + /// ### Never type fallback + /// + /// When the compiler sees a value of type [`!`] it implicitly inserts a coercion (if possible), + /// to allow type check to infer any type: + /// + /// ```ignore (illustrative-and-has-placeholders) + /// // this + /// let x: u8 = panic!(); + /// + /// // is (essentially) turned by the compiler into + /// let x: u8 = absurd(panic!()); + /// + /// // where absurd is a function with the following signature + /// // (it's sound, because `!` always marks unreachable code): + /// fn absurd(_: !) -> T { ... } + // FIXME: use `core::convert::absurd` here instead, once it's merged + /// ``` + /// + /// While it's convenient to be able to use non-diverging code in one of the branches (like + /// `if a { b } else { return }`) this could lead to compilation errors: + /// + /// ```compile_fail + /// // this + /// { panic!() }; + /// + /// // gets turned into this + /// { absurd(panic!()) }; // error: can't infer the type of `absurd` + /// ``` + /// + /// To prevent such errors, compiler remembers where it inserted `absurd` calls, and if it + /// can't infer their type, it sets the type to fallback. `{ absurd::(panic!()) };`. + /// This is what is known as "never type fallback". + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(never_type_fallback_flowing_into_unsafe)] + /// fn main() { + /// if true { + /// // return has type `!` which, is some cases, causes never type fallback + /// return + /// } else { + /// // `zeroed` is an unsafe function, which returns an unbounded type + /// unsafe { std::mem::zeroed() } + /// }; + /// // depending on the fallback, `zeroed` may create `()` (which is completely sound), + /// // or `!` (which is instant undefined behavior) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Due to historic reasons never type fallback was `()`, meaning that `!` got spontaneously + /// coerced to `()`. There are plans to change that, but they may make the code such as above + /// unsound. Instead of depending on the fallback, you should specify the type explicitly: + /// ``` + /// if true { + /// return + /// } else { + /// // type is explicitly specified, fallback can't hurt us no more + /// unsafe { std::mem::zeroed::<()>() } + /// }; + /// ``` + /// + /// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748). + /// + /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, + Warn, + "never type fallback affecting unsafe function calls" +} + declare_lint! { /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or @@ -4741,3 +4822,68 @@ declare_lint! { }; crate_level_only } + +declare_lint! { + /// The `uncovered_param_in_projection` lint detects a violation of one of Rust's orphan rules for + /// foreign trait implementations that concerns the use of type parameters inside trait associated + /// type paths ("projections") whose output may not be a local type that is mistakenly considered + /// to "cover" said parameters which is **unsound** and which may be rejected by a future version + /// of the compiler. + /// + /// Originally reported in [#99554]. + /// + /// [#99554]: https://github.com/rust-lang/rust/issues/99554 + /// + /// ### Example + /// + /// ```rust,ignore (dependent) + /// // dependency.rs + /// #![crate_type = "lib"] + /// + /// pub trait Trait {} + /// ``` + /// + /// ```edition2021,ignore (needs dependency) + /// // dependent.rs + /// trait Identity { + /// type Output; + /// } + /// + /// impl Identity for T { + /// type Output = T; + /// } + /// + /// struct Local; + /// + /// impl dependency::Trait for ::Output {} + /// + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + /// --> dependent.rs:11:6 + /// | + /// 11 | impl dependency::Trait for ::Output {} + /// | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + /// | + /// = 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 #124559 + /// = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + /// = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + /// = note: `#[warn(uncovered_param_in_projection)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// FIXME(fmease): Write explainer. + pub UNCOVERED_PARAM_IN_PROJECTION, + Warn, + "impl contains type parameters that are not covered", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #124559 ", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7f200a7b623d6..ed165188787a5 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate rustc_macros; - pub use self::Level::*; use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; @@ -11,6 +8,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::HashStableContext; use rustc_hir::HirId; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; use rustc_span::{sym, symbol::Ident, Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -323,7 +321,8 @@ pub struct Lint { pub future_incompatible: Option, - pub is_loaded: bool, + /// `true` if this lint is being loaded by another tool (e.g. Clippy). + pub is_externally_loaded: bool, /// `Some` if this lint is feature gated, otherwise `None`. pub feature_gate: Option, @@ -468,7 +467,7 @@ impl Lint { default_level: Level::Forbid, desc: "", edition_lint_opts: None, - is_loaded: false, + is_externally_loaded: false, report_in_external_macro: false, future_incompatible: None, feature_gate: None, @@ -817,7 +816,7 @@ macro_rules! declare_lint { name: stringify!($NAME), default_level: $crate::$Level, desc: $desc, - is_loaded: false, + is_externally_loaded: false, $($v: true,)* $(feature_gate: Some($gate),)? $(future_incompatible: Some($crate::FutureIncompatibleInfo { @@ -859,7 +858,7 @@ macro_rules! declare_tool_lint { edition_lint_opts: None, report_in_external_macro: $external, future_incompatible: None, - is_loaded: true, + is_externally_loaded: true, $(feature_gate: Some($gate),)? crate_level_only: false, ..$crate::Lint::default_fields_for_macro() diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 66ca94d1d9c7a..024f6f89a4b7f 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -50,7 +50,7 @@ fn detect_llvm_link() -> (&'static str, &'static str) { fn restore_library_path() { let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") { - env::set_var(&key, &env); + env::set_var(&key, env); } else { env::remove_var(&key); } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 6d578c97f3fe1..a493abbbc7e5a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -91,6 +91,8 @@ enum LLVMRustAttribute { AllocAlign = 39, SanitizeSafeStack = 40, FnRetThunkExtern = 41, + Writable = 42, + DeadOnUnwind = 43, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 565bdc3af03dd..20167a4b45ee2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -312,6 +312,16 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::SafeStack; case FnRetThunkExtern: return Attribute::FnRetThunkExtern; +#if LLVM_VERSION_GE(18, 0) + case Writable: + return Attribute::Writable; + case DeadOnUnwind: + return Attribute::DeadOnUnwind; +#else + case Writable: + case DeadOnUnwind: + report_fatal_error("Not supported on this LLVM version"); +#endif } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_macros/build.rs b/compiler/rustc_macros/build.rs index 717f8a922457d..62e827371a7f1 100644 --- a/compiler/rustc_macros/build.rs +++ b/compiler/rustc_macros/build.rs @@ -1,7 +1,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); - if !std::env::var("RUSTC_BOOTSTRAP").is_ok() { + if std::env::var("RUSTC_BOOTSTRAP").is_err() { eprintln!( "error: you are attempting to build the compiler without going through bootstrap" ); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index ced782cdbc016..45236771bce63 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -71,6 +71,7 @@ impl SubdiagnosticDerive { span_field: None, applicability: None, has_suggestion_parts: false, + has_subdiagnostic: false, is_enum, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) @@ -90,7 +91,7 @@ impl SubdiagnosticDerive { fn add_to_diag_with<__G, __F>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - #f: __F + #f: &__F ) where __G: rustc_errors::EmissionGuarantee, __F: rustc_errors::SubdiagMessageOp<__G>, @@ -133,6 +134,10 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> { /// during finalization if still `false`. has_suggestion_parts: bool, + /// Set to true when a `#[subdiagnostic]` field is encountered, used to suppress the error + /// emitted when no subdiagnostic kinds are specified on the variant itself. + has_subdiagnostic: bool, + /// Set to true when this variant is an enum variant rather than just the body of a struct. is_enum: bool, } @@ -373,6 +378,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { Ok(quote! {}) } + "subdiagnostic" => { + let f = &self.parent.f; + let diag = &self.parent.diag; + let binding = &info.binding; + self.has_subdiagnostic = true; + Ok(quote! { #binding.add_to_diag_with(#diag, #f); }) + } _ => { let mut span_attrs = vec![]; if kind_stats.has_multipart_suggestion { @@ -480,18 +492,6 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { pub(crate) fn into_tokens(&mut self) -> Result { let kind_slugs = self.identify_kind()?; - if kind_slugs.is_empty() { - if self.is_enum { - // It's okay for a variant to not be a subdiagnostic at all.. - return Ok(quote! {}); - } else { - // ..but structs should always be _something_. - throw_span_err!( - self.variant.ast().ident.span().unwrap(), - "subdiagnostic kind not specified" - ); - } - }; let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect(); @@ -510,6 +510,19 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .map(|binding| self.generate_field_attr_code(binding, kind_stats)) .collect(); + if kind_slugs.is_empty() { + if self.is_enum { + // It's okay for a variant to not be a subdiagnostic at all.. + return Ok(quote! {}); + } else if !self.has_subdiagnostic { + // ..but structs should always be _something_. + throw_span_err!( + self.variant.ast().ident.span().unwrap(), + "subdiagnostic kind not specified" + ); + } + }; + let span_field = self.span_field.value_ref(); let diag = &self.parent.diag; diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index eedc508fb1461..c7b7eadbd9d6b 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -144,6 +144,7 @@ decl_derive!( help, note, warning, + subdiagnostic, suggestion, suggestion_short, suggestion_hidden, diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 784fd4b3a3b72..888c2427d8f46 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -13,10 +13,10 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; use rustc_errors::DiagCtxt; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::IndexVec; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; use rustc_session::config::{self, CrateType, ExternLocation}; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; use rustc_session::lint; @@ -62,9 +62,6 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, - /// The interned [StableCrateId]s. - pub(crate) stable_crate_ids: StableCrateIdMap, - /// Unused externs of the crate unused_externs: Vec, } @@ -165,25 +162,27 @@ impl CStore { }) } - fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result { - assert_eq!(self.metas.len(), self.stable_crate_ids.len()); - let num = CrateNum::new(self.stable_crate_ids.len()); - if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { + fn intern_stable_crate_id<'tcx>( + &mut self, + root: &CrateRoot, + tcx: TyCtxt<'tcx>, + ) -> Result, CrateError> { + assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len()); + let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| { // Check for (potential) conflicts with the local crate if existing == LOCAL_CRATE { - Err(CrateError::SymbolConflictsCurrent(root.name())) + CrateError::SymbolConflictsCurrent(root.name()) } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { let crate_name0 = root.name(); - Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) + CrateError::StableCrateIdCollision(crate_name0, crate_name1) } else { - Err(CrateError::NotFound(root.name())) + CrateError::NotFound(root.name()) } - } else { - self.metas.push(None); - self.stable_crate_ids.insert(root.stable_crate_id(), num); - Ok(num) - } + })?; + + self.metas.push(None); + Ok(num) } pub fn has_crate_data(&self, cnum: CrateNum) -> bool { @@ -289,12 +288,7 @@ impl CStore { } } - pub fn new( - metadata_loader: Box, - local_stable_crate_id: StableCrateId, - ) -> CStore { - let mut stable_crate_ids = StableCrateIdMap::default(); - stable_crate_ids.insert(local_stable_crate_id, LOCAL_CRATE); + pub fn new(metadata_loader: Box) -> CStore { CStore { metadata_loader, // We add an empty entry for LOCAL_CRATE (which maps to zero) in @@ -307,7 +301,6 @@ impl CStore { alloc_error_handler_kind: None, has_global_allocator: false, has_alloc_error_handler: false, - stable_crate_ids, unused_externs: Vec::new(), } } @@ -416,7 +409,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let private_dep = self.is_private_dep(name.as_str(), private_dep); // Claim this crate number and cache it - let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; + let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?; + let cnum = feed.key(); info!( "register crate `{}` (cnum = {}. private_dep = {})", diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index b50ae05770936..fb0010f2c5d2e 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -4,8 +4,7 @@ use std::{ }; use rustc_errors::{codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::Diagnostic; -use rustc_session::config; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{sym, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -640,9 +639,7 @@ impl Diagnostic<'_, G> for CannotFindCrate { diag.arg("locator_triple", self.locator_triple.triple()); diag.code(E0463); diag.span(self.span); - if (self.crate_name == sym::std || self.crate_name == sym::core) - && self.locator_triple != TargetTriple::from_triple(config::host_triple()) - { + if self.crate_name == sym::std || self.crate_name == sym::core { if self.missing_core { diag.note(fluent::metadata_target_not_installed); } else { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index f133a2f5f73b2..c8162a1f0eead 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -6,7 +6,6 @@ #![feature(error_iter)] #![feature(extract_if)] #![feature(coroutines)] -#![feature(generic_nonzero)] #![feature(iter_from_coroutine)] #![feature(let_chains)] #![feature(if_let_guard)] @@ -20,8 +19,6 @@ extern crate proc_macro; -#[macro_use] -extern crate rustc_macros; #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 596da58b091f4..2a33088513b75 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1208,7 +1208,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self)) } - /// Iterates over the language items in the given crate. + /// Iterates over the lang items in the given crate. fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] { tcx.arena.alloc_from_iter( self.root @@ -1260,30 +1260,34 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { id: DefIndex, sess: &'a Session, ) -> impl Iterator + 'a { - iter::from_coroutine(move || { - if let Some(data) = &self.root.proc_macro_data { - // If we are loading as a proc macro, we want to return - // the view of this crate as a proc macro crate. - if id == CRATE_DEF_INDEX { - for child_index in data.macros.decode(self) { + iter::from_coroutine( + #[coroutine] + move || { + if let Some(data) = &self.root.proc_macro_data { + // If we are loading as a proc macro, we want to return + // the view of this crate as a proc macro crate. + if id == CRATE_DEF_INDEX { + for child_index in data.macros.decode(self) { + yield self.get_mod_child(child_index, sess); + } + } + } else { + // Iterate over all children. + let non_reexports = + self.root.tables.module_children_non_reexports.get(self, id); + for child_index in non_reexports.unwrap().decode(self) { yield self.get_mod_child(child_index, sess); } - } - } else { - // Iterate over all children. - let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); - for child_index in non_reexports.unwrap().decode(self) { - yield self.get_mod_child(child_index, sess); - } - let reexports = self.root.tables.module_children_reexports.get(self, id); - if !reexports.is_default() { - for reexport in reexports.decode((self, sess)) { - yield reexport; + let reexports = self.root.tables.module_children_reexports.get(self, id); + if !reexports.is_default() { + for reexport in reexports.decode((self, sess)) { + yield reexport; + } } } - } - }) + }, + ) } fn is_ctfe_mir_available(self, id: DefIndex) -> bool { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2935d5b8f6328..531b2e05411a0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -629,13 +629,6 @@ impl CrateStore for CStore { self.get_crate_data(cnum).root.stable_crate_id } - fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { - *self - .stable_crate_ids - .get(&stable_crate_id) - .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) - } - /// Returns the `DefKey` for a given `DefId`. This indicates the /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. @@ -657,7 +650,13 @@ fn provide_cstore_hooks(providers: &mut Providers) { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. let cstore = CStore::from_tcx(tcx.tcx); - let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + let cnum = *tcx + .untracked() + .stable_crate_ids + .read() + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")); + assert_ne!(cnum, LOCAL_CRATE); let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash); DefId { krate: cnum, index: def_index } }; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5b0be8ac230d4..c9cb2f5a2405c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -2,6 +2,7 @@ use crate::creader::CrateMetadataRef; use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; use rustc_data_structures::fx::FxHashMap; +use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable}; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::lib_features::FeatureStability; use table::TableBuilder; @@ -17,6 +18,7 @@ use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; +use rustc_macros::{MetadataDecodable, MetadataEncodable}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 0d3cffd204770..6e622b0405f0a 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,7 +1,7 @@ use std::fmt; use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage}; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::ty::Ty; diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 94d1039c763fa..34748afa863d0 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -15,6 +15,7 @@ use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, ExpnId}; /// Gather the LocalDefId for each item-like within a module, including items contained within diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 32f3a177508f7..1ac35314ead2f 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -2,6 +2,7 @@ use crate::ty; use crate::ty::Ty; use rustc_hir::HirId; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 62d7b7c28d1fb..aee97d772229b 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_type_ir::Canonical as IrCanonical; use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo; pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind}; diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 1384611e14679..f74f71b6b378a 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -4,6 +4,7 @@ pub mod unify_key; use crate::ty::Region; use crate::ty::{OpaqueTypeKey, Ty}; use rustc_data_structures::sync::Lrc; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; /// Requires that `region` must be equal to one of the regions in `choice_regions`. diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e52a5863fd03d..04fd4c8d0f7b9 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -35,9 +35,8 @@ #![feature(const_type_name)] #![feature(discriminant_kind)] #![feature(coroutines)] -#![feature(generic_nonzero)] +#![feature(stmt_expr_attributes)] #![feature(if_let_guard)] -#![feature(inline_const)] #![feature(iter_from_coroutine)] #![feature(negative_impls)] #![feature(never_type)] @@ -48,7 +47,6 @@ #![feature(trusted_len)] #![feature(type_alias_impl_trait)] #![feature(strict_provenance)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(rustc_attrs)] #![feature(control_flow_enum)] #![feature(trait_upcasting)] @@ -65,16 +63,8 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate rustc_macros; -#[macro_use] -extern crate rustc_data_structures; #[macro_use] extern crate tracing; -#[macro_use] -extern crate smallvec; #[cfg(test)] mod tests; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 8d9e0dfd86902..086582e60a3c0 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -4,6 +4,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::{Diag, DiagMessage, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; +use rustc_macros::HashStable; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, FutureIncompatibilityReason, Level, Lint, LintId, diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 674402cb4bf9b..589f274eb1766 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -1,7 +1,7 @@ use crate::ty; use rustc_hir::def::Res; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use smallvec::SmallVec; diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index ec9697bbd3558..3fa5054baed1e 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,5 +1,6 @@ use crate::mir::mono::Linkage; use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::symbol::Symbol; use rustc_target::abi::Align; use rustc_target::spec::SanitizerSet; @@ -48,7 +49,7 @@ pub struct CodegenFnAttrs { #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub struct CodegenFnAttrFlags(u32); -bitflags! { +bitflags::bitflags! { impl CodegenFnAttrFlags: u32 { /// `#[cold]`: a hint to LLVM that this function, when called, is never on /// the hot path. diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index a0497d805dad0..74a5dfb040099 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -1,4 +1,5 @@ use rustc_data_structures::sync::Lrc; +use rustc_macros::{Decodable, Encodable, HashStable}; use std::path::PathBuf; #[derive(HashStable)] diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs index e079843bfbc3c..e7d0cffc85cfb 100644 --- a/compiler/rustc_middle/src/middle/dependency_format.rs +++ b/compiler/rustc_middle/src/middle/dependency_format.rs @@ -4,6 +4,7 @@ //! For all the gory details, see the provider of the `dependency_formats` //! query. +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_session::config::CrateType; /// A list of dependencies for a certain crate type. diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index e30b6b203d73c..3b6eecb7fa041 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -1,7 +1,7 @@ use crate::ty::GenericArgsRef; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_macros::HashStable; +use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any @@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), Generic(DefId, GenericArgsRef<'tcx>), DropGlue(Ty<'tcx>), + AsyncDropGlueCtorShim(Ty<'tcx>), ThreadLocalShim(DefId), NoDefId(ty::SymbolName<'tcx>), } @@ -59,6 +60,9 @@ impl<'tcx> ExportedSymbol<'tcx> { ExportedSymbol::DropGlue(ty) => { tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) } + ExportedSymbol::AsyncDropGlueCtorShim(ty) => { + tcx.symbol_name(ty::Instance::resolve_async_drop_in_place(tcx, ty)) + } ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { def: ty::InstanceDef::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index a4e193ba2c942..4fd1c1f4a1b7d 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -1,4 +1,4 @@ -//! Detecting language items. +//! Detecting lang items. //! //! Language items are items that represent concepts intrinsic to the language //! itself. Examples are: diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index bdb2270611a9e..5c395afadd7f0 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -5,6 +5,7 @@ pub mod exported_symbols; pub mod lang_items; pub mod lib_features { use rustc_data_structures::unord::UnordMap; + use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::{symbol::Symbol, Span}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 5ae60e0427719..de07ba9700ac1 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::{HirId, HirIdMap, Node}; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::{Span, DUMMY_SP}; use std::fmt; @@ -153,7 +153,7 @@ rustc_index::newtype_index! { } // compilation error if size of `ScopeData` is not the same as a `u32` -static_assert_size!(ScopeData, 4); +rustc_data_structures::static_assert_size!(ScopeData, 4); impl Scope { /// Returns an item-local ID associated with this scope. diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 610afd95f3c6d..d0103f622313b 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_hir::{ItemLocalId, OwnerId}; -use rustc_macros::HashStable; +use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum ResolvedArg { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index c393287da95c9..67bd53f53daeb 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -14,6 +14,7 @@ use rustc_feature::GateIssue; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiag, Level, Lint, LintBuffer}; diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 1086d647721b7..f9398b254c7b1 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -7,6 +7,7 @@ use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::OnceLock; use rustc_index::{IndexSlice, IndexVec}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 596271c1e473f..d025dc360a248 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -1,6 +1,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use rustc_hir::def_id::DefId; +use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{HasDataLayout, Size}; @@ -71,7 +72,7 @@ pub enum ConstValue<'tcx> { } #[cfg(target_pointer_width = "64")] -static_assert_size!(ConstValue<'_>, 24); +rustc_data_structures::static_assert_size!(ConstValue<'_>, 24); impl<'tcx> ConstValue<'tcx> { #[inline] @@ -238,6 +239,20 @@ impl<'tcx> Const<'tcx> { } } + /// Determines whether we need to add this const to `required_consts`. This is the case if and + /// only if evaluating it may error. + #[inline] + pub fn is_required_const(&self) -> bool { + match self { + Const::Ty(c) => match c.kind() { + ty::ConstKind::Value(_) => false, // already a value, cannot error + _ => true, + }, + Const::Val(..) => false, // already a value, cannot error + Const::Unevaluated(..) => true, + } + } + #[inline] pub fn try_to_scalar(self) -> Option { match self { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index b1d0c815ae06b..9d9ca22247ad6 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -1,7 +1,7 @@ //! Metadata from source code coverage analysis and instrumentation. use rustc_index::IndexVec; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::{Span, Symbol}; use std::fmt::{self, Debug, Formatter}; @@ -132,7 +132,7 @@ pub enum CoverageKind { /// /// If this statement does not survive MIR optimizations, the condition would never be /// taken as evaluated. - CondBitmapUpdate { id: ConditionId, value: bool }, + CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 }, /// Marks the point in MIR control flow represented by a evaluated decision. /// @@ -140,7 +140,7 @@ pub enum CoverageKind { /// /// If this statement does not survive MIR optimizations, the decision would never be /// taken as evaluated. - TestVectorBitmapUpdate { bitmap_idx: u32 }, + TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 }, } impl Debug for CoverageKind { @@ -151,11 +151,17 @@ impl Debug for CoverageKind { BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), - CondBitmapUpdate { id, value } => { - write!(fmt, "CondBitmapUpdate({:?}, {:?})", id.index(), value) + CondBitmapUpdate { id, value, decision_depth } => { + write!( + fmt, + "CondBitmapUpdate({:?}, {:?}, depth={:?})", + id.index(), + value, + decision_depth + ) } - TestVectorBitmapUpdate { bitmap_idx } => { - write!(fmt, "TestVectorUpdate({:?})", bitmap_idx) + TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { + write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth) } } } @@ -269,6 +275,9 @@ pub struct FunctionCoverageInfo { pub mcdc_bitmap_bytes: u32, pub expressions: IndexVec, pub mappings: Vec, + /// The depth of the deepest decision is used to know how many + /// temp condbitmaps should be allocated for the function. + pub mcdc_max_decision_depth: u16, } /// Branch information recorded during THIR-to-MIR lowering, and stored in MIR. @@ -314,9 +323,12 @@ impl Default for ConditionInfo { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct MCDCBranchSpan { pub span: Span, - pub condition_info: ConditionInfo, + /// If `None`, this actually represents a normal branch span inserted for + /// code that was too complex for MC/DC. + pub condition_info: Option, pub true_marker: BlockMarkerId, pub false_marker: BlockMarkerId, + pub decision_depth: u16, } #[derive(Copy, Clone, Debug)] @@ -332,4 +344,5 @@ pub struct MCDCDecisionSpan { pub span: Span, pub conditions_num: usize, pub end_markers: Vec, + pub decision_depth: u16, } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 00faa21185371..9cc5c6a2ee940 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -14,6 +14,7 @@ use either::{Left, Right}; use rustc_ast::Mutability; use rustc_data_structures::intern::Interned; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index 2c6bb908f39f6..d60db775ff08a 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -5,6 +5,7 @@ use std::hash; use std::iter; use std::ops::Range; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::Size; use rustc_type_ir::{TyDecoder, TyEncoder}; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 9459af490e326..e974279f1917c 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -4,6 +4,7 @@ use std::cmp; use rustc_data_structures::sorted_map::SortedMap; +use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance}; diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 65ce1cd8f50c6..383241465c3d1 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -2,12 +2,12 @@ use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; +use crate::ty::{self, layout, tls, Ty, TyCtxt, ValTree}; use rustc_ast_ir::Mutability; use rustc_data_structures::sync::Lock; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; @@ -89,7 +89,7 @@ pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; pub type EvalToValTreeResult<'tcx> = Result>, ErrorHandled>; #[cfg(target_pointer_width = "64")] -static_assert_size!(InterpErrorInfo<'_>, 8); +rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); /// Packages the kind of error we got from the const code interpreter /// up with a Rust-level backtrace of where the error occurred. @@ -344,6 +344,11 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidFunctionPointer(Pointer), /// Using a pointer-not-to-a-vtable as vtable pointer. InvalidVTablePointer(Pointer), + /// Using a vtable for the wrong trait. + InvalidVTableTrait { + expected_trait: &'tcx ty::List>, + vtable_trait: Option>, + }, /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -414,34 +419,86 @@ impl From for ExpectedKind { #[derive(Debug)] pub enum ValidationErrorKind<'tcx> { - PointerAsInt { expected: ExpectedKind }, + PointerAsInt { + expected: ExpectedKind, + }, PartialPointer, - PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, - PtrToStatic { ptr_kind: PointerKind }, + PtrToUninhabited { + ptr_kind: PointerKind, + ty: Ty<'tcx>, + }, + PtrToStatic { + ptr_kind: PointerKind, + }, ConstRefToMutable, ConstRefToExtern, MutableRefToImmutable, UnsafeCellInImmutable, NullFnPtr, NeverVal, - NullablePtrOutOfRange { range: WrappingRange, max_value: u128 }, - PtrOutOfRange { range: WrappingRange, max_value: u128 }, - OutOfRange { value: String, range: WrappingRange, max_value: u128 }, - UninhabitedVal { ty: Ty<'tcx> }, - InvalidEnumTag { value: String }, + NullablePtrOutOfRange { + range: WrappingRange, + max_value: u128, + }, + PtrOutOfRange { + range: WrappingRange, + max_value: u128, + }, + OutOfRange { + value: String, + range: WrappingRange, + max_value: u128, + }, + UninhabitedVal { + ty: Ty<'tcx>, + }, + InvalidEnumTag { + value: String, + }, UninhabitedEnumVariant, - Uninit { expected: ExpectedKind }, - InvalidVTablePtr { value: String }, - InvalidMetaSliceTooLarge { ptr_kind: PointerKind }, - InvalidMetaTooLarge { ptr_kind: PointerKind }, - UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 }, - NullPtr { ptr_kind: PointerKind }, - DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String }, - DanglingPtrOutOfBounds { ptr_kind: PointerKind }, - DanglingPtrUseAfterFree { ptr_kind: PointerKind }, - InvalidBool { value: String }, - InvalidChar { value: String }, - InvalidFnPtr { value: String }, + Uninit { + expected: ExpectedKind, + }, + InvalidVTablePtr { + value: String, + }, + InvalidMetaWrongTrait { + expected_trait: &'tcx ty::List>, + vtable_trait: Option>, + }, + InvalidMetaSliceTooLarge { + ptr_kind: PointerKind, + }, + InvalidMetaTooLarge { + ptr_kind: PointerKind, + }, + UnalignedPtr { + ptr_kind: PointerKind, + required_bytes: u64, + found_bytes: u64, + }, + NullPtr { + ptr_kind: PointerKind, + }, + DanglingPtrNoProvenance { + ptr_kind: PointerKind, + pointer: String, + }, + DanglingPtrOutOfBounds { + ptr_kind: PointerKind, + }, + DanglingPtrUseAfterFree { + ptr_kind: PointerKind, + }, + InvalidBool { + value: String, + }, + InvalidChar { + value: String, + }, + InvalidFnPtr { + value: String, + }, } /// Error information for when the program did something that might (or might not) be correct diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 6275942bafe65..ee3cdf36820de 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -131,7 +131,7 @@ use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_data_structures::tiny_list::TinyList; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::{AddressSpace, Endian, HasDataLayout}; diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index e2767ee298958..a0acacc844fd5 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -1,6 +1,7 @@ use super::{AllocId, InterpResult}; -use rustc_macros::HashStable; +use rustc_data_structures::static_assert_size; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_target::abi::{HasDataLayout, Size}; use std::{fmt, num::NonZero}; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 9728967860a05..c5c87c506b77f 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -6,7 +6,7 @@ use rustc_apfloat::{ ieee::{Double, Half, Quad, Single}, Float, }; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_target::abi::{HasDataLayout, Size}; use crate::ty::ScalarInt; @@ -38,7 +38,7 @@ pub enum Scalar { } #[cfg(target_pointer_width = "64")] -static_assert_size!(Scalar, 24); +rustc_data_structures::static_assert_size!(Scalar, 24); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 43e4e8216e1a6..25cc9ac47c83a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -20,6 +20,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::{ self as hir, BindingMode, ByRef, CoroutineDesugaring, CoroutineKind, HirId, ImplicitSelfKind, }; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -701,10 +702,7 @@ impl<'tcx> Body<'tcx> { env, crate::ty::EarlyBinder::bind(constant.const_), ); - let Some(bits) = mono_literal.try_eval_bits(tcx, env) else { - bug!("Couldn't evaluate constant {:?} in mono {:?}", constant, instance); - }; - bits + mono_literal.try_eval_bits(tcx, env) }; let TerminatorKind::SwitchInt { discr, targets } = &block.terminator().kind else { @@ -714,7 +712,7 @@ impl<'tcx> Body<'tcx> { // If this is a SwitchInt(const _), then we can just evaluate the constant and return. let discr = match discr { Operand::Constant(constant) => { - let bits = eval_mono_const(constant); + let bits = eval_mono_const(constant)?; return Some((bits, targets)); } Operand::Move(place) | Operand::Copy(place) => place, @@ -748,7 +746,7 @@ impl<'tcx> Body<'tcx> { match rvalue { Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), Rvalue::Use(Operand::Constant(constant)) => { - let bits = eval_mono_const(constant); + let bits = eval_mono_const(constant)?; Some((bits, targets)) } _ => None, diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 43e1318a75ab1..6d4585cfbc66a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -9,6 +9,7 @@ use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; use rustc_index::Idx; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; use rustc_span::symbol::Symbol; @@ -65,7 +66,9 @@ impl<'tcx> MonoItem<'tcx> { match instance.def { // "Normal" functions size estimate: the number of // statements, plus one for the terminator. - InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { + InstanceDef::Item(..) + | InstanceDef::DropGlue(..) + | InstanceDef::AsyncDropGlueCtorShim(..) => { let mir = tcx.instance_mir(instance.def); mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() } @@ -406,7 +409,8 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) => None, + | InstanceDef::FnPtrAddrShim(..) + | InstanceDef::AsyncDropGlueCtorShim(..) => None, } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8291404ebf31f..5aaa1c30cade0 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -187,6 +187,17 @@ fn dump_path<'tcx>( })); s } + ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => { + // Unfortunately, pretty-printed typed are not very filename-friendly. + // We dome some filtering. + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } _ => String::new(), }; @@ -485,20 +496,27 @@ fn write_coverage_branch_info( )?; } - for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in - mcdc_branch_spans + for coverage::MCDCBranchSpan { + span, + condition_info, + true_marker, + false_marker, + decision_depth, + } in mcdc_branch_spans { writeln!( w, - "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", - condition_info.condition_id + "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}", + condition_info.map(|info| info.condition_id) )?; } - for coverage::MCDCDecisionSpan { span, conditions_num, end_markers } in mcdc_decision_spans { + for coverage::MCDCDecisionSpan { span, conditions_num, end_markers, decision_depth } in + mcdc_decision_spans + { writeln!( w, - "{INDENT}coverage mcdc decision {{ conditions_num: {conditions_num:?}, end: {end_markers:?} }} => {span:?}" + "{INDENT}coverage mcdc decision {{ conditions_num: {conditions_num:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" )?; } @@ -974,7 +992,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { Ref(region, borrow_kind, ref place) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", - BorrowKind::Fake => "fake ", + BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ", + BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ", BorrowKind::Mut { .. } => "mut ", }; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index e3f58729fbd15..9a7af6135e46f 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 069c8019cb2c8..375f1f15a39ed 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -236,6 +236,11 @@ impl<'tcx> PlaceRef<'tcx> { } } + #[inline] + pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { + Place { local: self.local, projection: tcx.mk_place_elems(self.projection) } + } + #[inline] pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { if let &[ref proj_base @ .., elem] = self.projection { @@ -446,7 +451,7 @@ impl<'tcx> Rvalue<'tcx> { impl BorrowKind { pub fn mutability(&self) -> Mutability { match *self { - BorrowKind::Shared | BorrowKind::Fake => Mutability::Not, + BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, } } @@ -454,7 +459,7 @@ impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared - | BorrowKind::Fake + | BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => { false } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index db13bb9a3e8e4..4278ce823d0e0 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -17,6 +17,7 @@ use rustc_data_structures::packed::Pu128; use rustc_hir::def_id::DefId; use rustc_hir::CoroutineKind; use rustc_index::IndexVec; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -165,13 +166,16 @@ pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. For example, a shallow borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. + /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either + /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]). /// - /// This is used when lowering matches: when matching on a place we want to - /// ensure that place have the same value from the start of the match until - /// an arm is selected. This prevents this code from compiling: + /// This is used when lowering index expressions and matches. This is used to prevent code like + /// the following from compiling: + /// ```compile_fail,E0510 + /// let mut x: &[_] = &[[0, 1]]; + /// let y: &[_] = &[]; + /// let _ = x[0][{x = y; 1}]; + /// ``` /// ```compile_fail,E0510 /// let mut x = &Some(0); /// match *x { @@ -180,11 +184,8 @@ pub enum BorrowKind { /// Some(_) => (), /// } /// ``` - /// This can't be a shared borrow because mutably borrowing (*x as Some).0 - /// should not prevent `if let None = x { ... }`, for example, because the - /// mutating `(*x as Some).0` can't affect the discriminant of `x`. /// We can also report errors with this kind of borrow differently. - Fake, + Fake(FakeBorrowKind), /// Data is mutable and not aliasable. Mut { kind: MutBorrowKind }, @@ -240,6 +241,57 @@ pub enum MutBorrowKind { ClosureCapture, } +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum FakeBorrowKind { + /// A shared shallow borrow. The immediately borrowed place must be immutable, but projections + /// from it don't need to be. For example, a shallow borrow of `a.b` doesn't conflict with a + /// mutable borrow of `a.b.c`. + /// + /// This is used when lowering matches: when matching on a place we want to ensure that place + /// have the same value from the start of the match until an arm is selected. This prevents this + /// code from compiling: + /// ```compile_fail,E0510 + /// let mut x = &Some(0); + /// match *x { + /// None => (), + /// Some(_) if { x = &None; false } => (), + /// Some(_) => (), + /// } + /// ``` + /// This can't be a shared borrow because mutably borrowing `(*x as Some).0` should not checking + /// the discriminant or accessing other variants, because the mutating `(*x as Some).0` can't + /// affect the discriminant of `x`. E.g. the following is allowed: + /// ```rust + /// let mut x = Some(0); + /// match x { + /// Some(_) + /// if { + /// if let Some(ref mut y) = x { + /// *y += 1; + /// }; + /// true + /// } => {} + /// _ => {} + /// } + /// ``` + Shallow, + /// A shared (deep) borrow. Data must be immutable and is aliasable. + /// + /// This is used when lowering deref patterns, where shallow borrows wouldn't prevent something + /// like: + // ```compile_fail + // let mut b = Box::new(false); + // match b { + // deref!(true) => {} // not reached because `*b == false` + // _ if { *b = true; false } => {} // not reached because the guard is `false` + // deref!(false) => {} // not reached because the guard changed it + // // UB because we reached the unreachable. + // } + // ``` + Deep, +} + /////////////////////////////////////////////////////////////////////////// // Statements @@ -1471,6 +1523,7 @@ pub enum BinOp { #[cfg(target_pointer_width = "64")] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(AggregateKind<'_>, 32); static_assert_size!(Operand<'_>, 24); diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index abe99f3e95c2e..3881723c5ec9c 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -15,7 +15,7 @@ pub struct PlaceTy<'tcx> { // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. #[cfg(target_pointer_width = "64")] -static_assert_size!(PlaceTy<'_>, 16); +rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16); impl<'tcx> PlaceTy<'tcx> { #[inline] @@ -294,7 +294,7 @@ impl BorrowKind { // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. - BorrowKind::Fake => hir::Mutability::Not, + BorrowKind::Fake(_) => hir::Mutability::Not, } } } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 58a27c1f9ef58..f95afb199f7f9 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,10 +1,10 @@ /// Functionality for terminators and helper types that appear in terminators. use rustc_hir::LangItem; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use super::TerminatorKind; use rustc_data_structures::packed::Pu128; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use std::slice; use super::*; diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index fc1ab0f12ac9e..d97abc3f1904f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -350,12 +350,14 @@ macro_rules! make_mir_visitor { receiver_by_ref: _, } | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | + ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, None) | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | ty::InstanceDef::DropGlue(_def_id, Some(ty)) | ty::InstanceDef::CloneShim(_def_id, ty) | - ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => { + ty::InstanceDef::FnPtrAddrShim(_def_id, ty) | + ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } @@ -653,7 +655,7 @@ macro_rules! make_mir_visitor { BorrowKind::Shared => PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow ), - BorrowKind::Fake => PlaceContext::NonMutatingUse( + BorrowKind::Fake(_) => PlaceContext::NonMutatingUse( NonMutatingUseContext::FakeBorrow ), BorrowKind::Mut { .. } => @@ -1282,6 +1284,8 @@ pub enum NonMutatingUseContext { /// Shared borrow. SharedBorrow, /// A fake borrow. + /// FIXME: do we need to distinguish shallow and deep fake borrows? In fact, do we need to + /// distinguish fake and normal deep borrows? FakeBorrow, /// AddressOf for *const pointer. AddressOf, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0d625ff0faeb5..c2f7a227f6661 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -72,6 +72,7 @@ use rustc_hir::def_id::{ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_index::IndexVec; +use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{try_get_cached, QueryCache, QueryMode, QueryState}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; @@ -846,8 +847,10 @@ rustc_queries! { separate_provide_extern } - query issue33140_self_ty(key: DefId) -> Option>> { - desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } + query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( + key: DefId + ) -> Option>> { + desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) } } /// Maps a `DefId` of a type to a list of its inherent impls. @@ -975,10 +978,6 @@ rustc_queries! { cache_on_disk_if { true } } - query has_typeck_results(def_id: DefId) -> bool { - desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } - } - query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } ensure_forwards_result_if_red @@ -1344,6 +1343,14 @@ rustc_queries! { query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } } + /// Query backing `Ty::has_surface_async_drop`. + query has_surface_async_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` has `AsyncDrop` implementation", env.value } + } + /// Query backing `Ty::has_surface_drop`. + query has_surface_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` has `Drop` implementation", env.value } + } /// Query backing `Ty::needs_drop`. query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index db1b5a74f0ae8..2dcb58729ff96 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -6,6 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; +use rustc_macros::{Decodable, Encodable}; use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 038d3fe93c4bd..8a4e3ab0e619a 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -12,6 +12,7 @@ use rustc_data_structures::sync::AtomicU64; use rustc_data_structures::sync::WorkerLocal; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; +use rustc_macros::HashStable; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::dep_graph::SerializedDepNodeIndex; pub(crate) use rustc_query_system::query::QueryJobId; diff --git a/compiler/rustc_middle/src/tests.rs b/compiler/rustc_middle/src/tests.rs index 49960cc0bb2a2..6c2e5f63418a7 100644 --- a/compiler/rustc_middle/src/tests.rs +++ b/compiler/rustc_middle/src/tests.rs @@ -1,13 +1,9 @@ -use super::*; - -// FIXME(#27438): right now the unit tests of rustc_middle don't refer to any actual -// functions generated in rustc_data_structures (all -// references are through generic functions), but statics are -// referenced from time to time. Due to this bug we won't -// actually correctly link in the statics unless we also -// reference a function, so be sure to reference a dummy -// function. +// FIXME(#27438): Right now, the unit tests of `rustc_middle` don't refer to any actual functions +// generated in `rustc_data_structures` (all references are through generic functions), +// but statics are referenced from time to time. Due to this Windows `dllimport` bug +// we won't actually correctly link in the statics unless we also reference a function, +// so be sure to reference a dummy function. #[test] fn noop() { - rustc_data_structures::__noop_fix_for_27438(); + rustc_data_structures::__noop_fix_for_windows_dllimport_issue(); } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index d52b1efce4b08..a7d8ead567738 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::newtype_index; use rustc_index::IndexVec; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; @@ -642,7 +643,7 @@ impl<'tcx> Pat<'tcx> { AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } - | DerefPattern { subpattern } + | DerefPattern { subpattern, .. } | InlineConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) @@ -760,6 +761,7 @@ pub enum PatKind<'tcx> { /// Deref pattern, written `box P` for now. DerefPattern { subpattern: Box>, + mutability: hir::Mutability, }, /// One of the following: @@ -1166,7 +1168,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } write!(f, "{subpattern}") } - PatKind::DerefPattern { ref subpattern } => { + PatKind::DerefPattern { ref subpattern, .. } => { write!(f, "deref!({subpattern})") } PatKind::Constant { value } => write!(f, "{value}"), @@ -1208,6 +1210,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { #[cfg(target_pointer_width = "64")] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index e42b85530b502..f198881043739 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -229,7 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } - | DerefPattern { subpattern } + | DerefPattern { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern), Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ceee3ea48e388..1ae037e09a75e 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -20,10 +20,13 @@ use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::HirId; +use rustc_macros::{ + Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, +}; use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::hash::{Hash, Hasher}; @@ -328,11 +331,16 @@ pub enum ObligationCauseCode<'tcx> { /// `static` items must have `Sync` type. SharedStatic, + /// Derived obligation (i.e. theoretical `where` clause) on a built-in + /// implementation like `Copy` or `Sized`. BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + /// Derived obligation (i.e. `where` clause) on an user-provided impl + /// or a trait alias. ImplDerivedObligation(Box>), - DerivedObligation(DerivedObligationCause<'tcx>), + /// Derived obligation for WF goals. + WellFormedDerivedObligation(DerivedObligationCause<'tcx>), FunctionArgumentObligation { /// The node of the relevant argument in the function call. @@ -487,7 +495,7 @@ pub enum WellFormedLoc { /// The index of the parameter to use. /// Parameters are indexed from 0, with the return type /// being the last 'parameter' - param_idx: u16, + param_idx: usize, }, } @@ -534,7 +542,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { match self { FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)), BuiltinDerivedObligation(derived) - | DerivedObligation(derived) + | WellFormedDerivedObligation(derived) | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => { Some((&derived.parent_code, Some(derived.parent_trait_pred))) } @@ -552,7 +560,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -static_assert_size!(ObligationCauseCode<'_>, 48); +rustc_data_structures::static_assert_size!(ObligationCauseCode<'_>, 48); #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum StatementAsExpression { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 12e4f70ba5751..70f3532e3ab15 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -10,11 +10,13 @@ use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; pub mod type_op { use crate::ty::fold::TypeFoldable; use crate::ty::{Predicate, Ty, TyCtxt, UserType}; + use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use std::fmt; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index c35524373c7ac..c8caf228ffb5b 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -10,6 +10,7 @@ use rustc_errors::ErrorGuaranteed; use crate::ty; use rustc_hir::def_id::DefId; +use rustc_macros::{HashStable, TypeVisitable}; use rustc_query_system::cache::Cache; pub type SelectionCache<'tcx> = Cache< diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 13504c6ae930a..4c34bf88c7f96 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,5 +1,6 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::def_id::DefId; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; @@ -332,4 +333,9 @@ pub enum CandidateSource { /// } /// ``` AliasBound, + /// A candidate that is registered only during coherence to represent some + /// yet-unknown impl that could be produced downstream without violating orphan + /// rules. + // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`. + CoherenceUnknowable, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 52cdbae1e564f..cddf9d5f874a3 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -24,6 +24,7 @@ use super::{ }; use crate::{infer::canonical::CanonicalVarValues, ty}; use format::ProofTreeFormatter; +use rustc_macros::{TypeFoldable, TypeVisitable}; use std::fmt::{Debug, Write}; mod format; @@ -60,14 +61,14 @@ pub struct GoalEvaluation<'tcx> { pub evaluation: CanonicalGoalEvaluation<'tcx>, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub struct CanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, pub kind: CanonicalGoalEvaluationKind<'tcx>, pub result: QueryResult<'tcx>, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub enum CanonicalGoalEvaluationKind<'tcx> { Overflow, CycleInStack, @@ -86,7 +87,7 @@ pub struct AddedGoalsEvaluation<'tcx> { pub result: Result, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub struct GoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, @@ -102,6 +103,7 @@ pub struct Probe<'tcx> { /// What happened inside of this probe in chronological order. pub steps: Vec>, pub kind: ProbeKind<'tcx>, + pub final_state: CanonicalState<'tcx, ()>, } impl Debug for Probe<'_> { @@ -121,6 +123,12 @@ pub enum ProbeStep<'tcx> { /// used whenever there are multiple candidates to prove the /// current goalby . NestedProbe(Probe<'tcx>), + /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with + /// `Certainty` was made. This is the certainty passed in, so it's not unified + /// with the certainty of the `try_evaluate_added_goals` that is done within; + /// if it's `Certainty::Yes`, then we can trust that the candidate is "finished" + /// and we didn't force ambiguity for some reason. + MakeCanonicalResponse { shallow_certainty: Certainty }, } /// What kind of probe we're in. In case the probe represents a candidate, or @@ -134,10 +142,6 @@ pub enum ProbeKind<'tcx> { TryNormalizeNonRigid { result: QueryResult<'tcx> }, /// Probe entered when normalizing the self ty during candidate assembly NormalizedSelfTyAssembly, - /// Some candidate to prove the current goal. - /// - /// FIXME: Remove this in favor of always using more strongly typed variants. - MiscCandidate { name: &'static str, result: QueryResult<'tcx> }, /// A candidate for proving a trait or alias-relate goal. TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> }, /// Used in the probe that wraps normalizing the non-self type for the unsize @@ -147,4 +151,6 @@ pub enum ProbeKind<'tcx> { /// do a probe to find out what projection type(s) may be used to prove that /// the source type upholds all of the target type's object bounds. UpcastProjectionCompatibility, + /// Try to unify an opaque type with an existing key in the storage. + OpaqueTypeStorageLookup { result: QueryResult<'tcx> }, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 98f01fe877244..2d73be387fdcd 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -112,8 +112,8 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeKind::UpcastProjectionCompatibility => { write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:") } - ProbeKind::MiscCandidate { name, result } => { - write!(self.f, "CANDIDATE {name}: {result:?}") + ProbeKind::OpaqueTypeStorageLookup { result } => { + write!(self.f, "PROBING FOR AN EXISTING OPAQUE: {result:?}") } ProbeKind::TraitCandidate { source, result } => { write!(self.f, "CANDIDATE {source:?}: {result:?}") @@ -132,6 +132,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { } ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?, ProbeStep::NestedProbe(probe) => this.format_probe(probe)?, + ProbeStep::MakeCanonicalResponse { shallow_certainty } => { + writeln!(this.f, "EVALUATE GOALS AND MAKE RESPONSE: {shallow_certainty:?}")? + } } } Ok(()) diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index ba29d4040a1e7..ff5d51bcb66f5 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -5,6 +5,7 @@ use crate::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, DefIdMap}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::symbol::sym; /// A per-trait graph of impls in specialization order. At the moment, this diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 570f896ba299b..dc46b470b6f48 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -4,6 +4,7 @@ use crate::ty::{ TypeVisitableExt, }; use rustc_errors::ErrorGuaranteed; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; #[derive(Hash, Debug, Clone, Copy, Ord, PartialOrd, PartialEq, Eq)] #[derive(TyDecodable, TyEncodable, HashStable, TypeVisitable, TypeFoldable)] diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index c3e8991c63a20..9badf65115ed4 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -1,7 +1,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; use rustc_target::abi::FieldIdx; diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index a7f1ba46b6170..77da3fbe1d799 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -12,6 +12,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_index::{IndexSlice, IndexVec}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; @@ -26,7 +27,7 @@ use super::{Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, Var #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub struct AdtFlags(u16); -bitflags! { +bitflags::bitflags! { impl AdtFlags: u16 { const NO_ADT_FLAGS = 0; /// Indicates whether the ADT is an enum. @@ -582,8 +583,7 @@ impl<'tcx> AdtDef<'tcx> { } } -#[derive(Clone, Copy, Debug)] -#[derive(HashStable)] +#[derive(Clone, Copy, Debug, HashStable)] pub enum Representability { Representable, Infinite(ErrorGuaranteed), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 94a5ff13158a2..1cdde3f057c67 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -3,6 +3,7 @@ use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::symbol::{Ident, Symbol}; use super::{TyCtxt, Visibility}; diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c9fd20bc1126a..26c5a865fdc22 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -4,7 +4,7 @@ use crate::ty::{self, Ty}; use rustc_middle::mir; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// Types that are represented as ints. #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 11167515b7ca0..bade0d564156f 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -11,6 +11,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirId; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; @@ -422,49 +423,53 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( child_captures: impl IntoIterator>, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, ) -> impl Iterator + Captures<'a> + Captures<'tcx> { - std::iter::from_coroutine(move || { - let mut child_captures = child_captures.into_iter().enumerate().peekable(); - - // One parent capture may correspond to several child captures if we end up - // refining the set of captures via edition-2021 precise captures. We want to - // match up any number of child captures with one parent capture, so we keep - // peeking off this `Peekable` until the child doesn't match anymore. - for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { - // Make sure we use every field at least once, b/c why are we capturing something - // if it's not used in the inner coroutine. - let mut field_used_at_least_once = false; - - // A parent matches a child if they share the same prefix of projections. - // The child may have more, if it is capturing sub-fields out of - // something that is captured by-move in the parent closure. - while child_captures.peek().map_or(false, |(_, child_capture)| { - child_prefix_matches_parent_projections(parent_capture, child_capture) - }) { - let (child_field_idx, child_capture) = child_captures.next().unwrap(); - // This analysis only makes sense if the parent capture is a - // prefix of the child capture. - assert!( - child_capture.place.projections.len() >= parent_capture.place.projections.len(), - "parent capture ({parent_capture:#?}) expected to be prefix of \ + std::iter::from_coroutine( + #[coroutine] + move || { + let mut child_captures = child_captures.into_iter().enumerate().peekable(); + + // One parent capture may correspond to several child captures if we end up + // refining the set of captures via edition-2021 precise captures. We want to + // match up any number of child captures with one parent capture, so we keep + // peeking off this `Peekable` until the child doesn't match anymore. + for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { + // Make sure we use every field at least once, b/c why are we capturing something + // if it's not used in the inner coroutine. + let mut field_used_at_least_once = false; + + // A parent matches a child if they share the same prefix of projections. + // The child may have more, if it is capturing sub-fields out of + // something that is captured by-move in the parent closure. + while child_captures.peek().map_or(false, |(_, child_capture)| { + child_prefix_matches_parent_projections(parent_capture, child_capture) + }) { + let (child_field_idx, child_capture) = child_captures.next().unwrap(); + // This analysis only makes sense if the parent capture is a + // prefix of the child capture. + assert!( + child_capture.place.projections.len() + >= parent_capture.place.projections.len(), + "parent capture ({parent_capture:#?}) expected to be prefix of \ child capture ({child_capture:#?})" - ); + ); - yield for_each( - (parent_field_idx, parent_capture), - (child_field_idx, child_capture), - ); + yield for_each( + (parent_field_idx, parent_capture), + (child_field_idx, child_capture), + ); - field_used_at_least_once = true; - } + field_used_at_least_once = true; + } - // Make sure the field was used at least once. - assert!( - field_used_at_least_once, - "we captured {parent_capture:#?} but it was not used in the child coroutine?" - ); - } - assert_eq!(child_captures.next(), None, "leftover child captures?"); - }) + // Make sure the field was used at least once. + assert!( + field_used_at_least_once, + "we captured {parent_capture:#?} but it was not used in the child coroutine?" + ); + } + assert_eq!(child_captures.next(), None, "leftover child captures?"); + }, + ) } fn child_prefix_matches_parent_projections( diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index fd4573c16031e..a65b3a41ade3b 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -6,7 +6,7 @@ use rustc_error_messages::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_type_ir::ConstKind as IrConstKind; use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo}; @@ -23,7 +23,7 @@ pub use valtree::*; pub type ConstKind<'tcx> = IrConstKind>; #[cfg(target_pointer_width = "64")] -static_assert_size!(ConstKind<'_>, 32); +rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); /// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] @@ -63,7 +63,7 @@ pub struct ConstData<'tcx> { } #[cfg(target_pointer_width = "64")] -static_assert_size!(ConstData<'_>, 40); +rustc_data_structures::static_assert_size!(ConstData<'_>, 40); impl<'tcx> Const<'tcx> { #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index a7e0a0402ce98..7e49b0ac915c6 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -4,7 +4,7 @@ use crate::ty::abstract_const::CastKind; use crate::ty::GenericArgsRef; use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; /// An unevaluated (potentially generic) constant used in the type-system. #[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] @@ -72,4 +72,4 @@ pub enum Expr<'tcx> { } #[cfg(target_pointer_width = "64")] -static_assert_size!(Expr<'_>, 24); +rustc_data_structures::static_assert_size!(Expr<'_>, 24); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6275c5d2a1194..d2eacdf762f1b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -56,7 +56,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_index::IndexVec; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -565,13 +565,6 @@ impl<'tcx> TyCtxt<'tcx> { TyCtxtFeed { tcx: self, key: () } } - /// Can only be fed before queries are run, and is thus exempt from any - /// incremental issues. Do not use except for the initial query feeding. - pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> { - self.dep_graph.assert_ignored(); - TyCtxtFeed { tcx: self, key: LOCAL_CRATE } - } - /// Only used in the resolver to register the `CRATE_DEF_ID` `DefId` and feed /// some queries for it. It will panic if used twice. pub fn create_local_crate_def_id(self, span: Span) -> TyCtxtFeed<'tcx, LocalDefId> { @@ -817,6 +810,17 @@ impl CurrentGcx { } impl<'tcx> TyCtxt<'tcx> { + pub fn has_typeck_results(self, def_id: LocalDefId) -> bool { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let typeck_root_def_id = self.typeck_root_def_id(def_id.to_def_id()); + if typeck_root_def_id != def_id.to_def_id() { + return self.has_typeck_results(typeck_root_def_id.expect_local()); + } + + self.hir_node_by_def_id(def_id).body_id().is_some() + } + /// Expects a body and returns its codegen attributes. /// /// Unlike `codegen_fn_attrs`, this returns `CodegenFnAttrs::EMPTY` for @@ -1140,7 +1144,12 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) { LOCAL_CRATE } else { - self.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id) + *self + .untracked() + .stable_crate_ids + .read() + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) } } @@ -1256,26 +1265,42 @@ impl<'tcx> TyCtxt<'tcx> { feed } + pub fn create_crate_num( + self, + stable_crate_id: StableCrateId, + ) -> Result, CrateNum> { + if let Some(&existing) = self.untracked().stable_crate_ids.read().get(&stable_crate_id) { + return Err(existing); + } + + let num = CrateNum::new(self.untracked().stable_crate_ids.read().len()); + self.untracked().stable_crate_ids.write().insert(stable_crate_id, num); + Ok(TyCtxtFeed { key: num, tcx: self }) + } + pub fn iter_local_def_id(self) -> impl Iterator + 'tcx { // Create a dependency to the red node to be sure we re-execute this when the amount of // definitions change. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); let definitions = &self.untracked.definitions; - std::iter::from_coroutine(|| { - let mut i = 0; - - // Recompute the number of definitions each time, because our caller may be creating - // new ones. - while i < { definitions.read().num_definitions() } { - let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); - yield LocalDefId { local_def_index }; - i += 1; - } + std::iter::from_coroutine( + #[coroutine] + || { + let mut i = 0; + + // Recompute the number of definitions each time, because our caller may be creating + // new ones. + while i < { definitions.read().num_definitions() } { + let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); + yield LocalDefId { local_def_index }; + i += 1; + } - // Freeze definitions once we finish iterating on them, to prevent adding new ones. - definitions.freeze(); - }) + // Freeze definitions once we finish iterating on them, to prevent adding new ones. + definitions.freeze(); + }, + ) } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index cc1d6e50f6d9a..8c3ee6955f5d2 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -279,24 +279,29 @@ pub fn suggest_constraining_type_params<'a>( constraint.sort(); constraint.dedup(); let constraint = constraint.join(" + "); - let mut suggest_restrict = |span, bound_list_non_empty| { - suggestions.push(( - span, - if span_to_replace.is_some() { - constraint.clone() - } else if constraint.starts_with('<') { - constraint.to_string() - } else if bound_list_non_empty { - format!(" + {constraint}") - } else { - format!(" {constraint}") - }, - SuggestChangingConstraintsMessage::RestrictBoundFurther, - )) + let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| { + let suggestion = if span_to_replace.is_some() { + constraint.clone() + } else if constraint.starts_with('<') { + constraint.to_string() + } else if bound_list_non_empty { + format!(" + {constraint}") + } else { + format!(" {constraint}") + }; + + use SuggestChangingConstraintsMessage::RestrictBoundFurther; + + if let Some(open_paren_sp) = open_paren_sp { + suggestions.push((open_paren_sp, "(".to_string(), RestrictBoundFurther)); + suggestions.push((span, format!("){suggestion}"), RestrictBoundFurther)); + } else { + suggestions.push((span, suggestion, RestrictBoundFurther)); + } }; if let Some(span) = span_to_replace { - suggest_restrict(span, true); + suggest_restrict(span, true, None); continue; } @@ -327,8 +332,8 @@ pub fn suggest_constraining_type_params<'a>( // -- // | // replace with: `T: Bar +` - if let Some(span) = generics.bounds_span_for_suggestions(param.def_id) { - suggest_restrict(span, true); + if let Some((span, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { + suggest_restrict(span, true, open_paren_sp); continue; } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index ce85c28ece89b..71437ce1df9de 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -4,6 +4,7 @@ use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::def_id::DefId; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_span::symbol::Symbol; use rustc_target::spec::abi; use std::borrow::Cow; diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 7c925d5fbb660..15f048ab598c9 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -2,6 +2,7 @@ use crate::mir::Mutability; use crate::ty::GenericArgKind; use crate::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use std::fmt::Debug; use std::hash::Hash; use std::iter; @@ -58,30 +59,6 @@ pub enum TreatParams { /// This also treats projections with inference variables as infer vars /// since they could be further normalized. ForLookup, - /// Treat parameters as placeholders in the given environment. This is the - /// correct mode for *lookup*, as during candidate selection. - /// - /// N.B. during deep rejection, this acts identically to `ForLookup`. - /// - /// FIXME(-Znext-solver): Remove this variant and cleanup - /// the code. - NextSolverLookup, -} - -/// During fast-rejection, we have the choice of treating projection types -/// as either simplifiable or not, depending on whether we expect the projection -/// to be normalized/rigid. -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum TreatProjections { - /// In the old solver we don't try to normalize projections - /// when looking up impls and only access them by using the - /// current self type. This means that if the self type is - /// a projection which could later be normalized, we must not - /// treat it as rigid. - ForLookup, - /// We can treat projections in the self type as opaque as - /// we separately look up impls for the normalized self type. - NextSolverLookup, } /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. @@ -139,21 +116,17 @@ pub fn simplify_type<'tcx>( ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), ty::Placeholder(..) => Some(SimplifiedType::Placeholder), ty::Param(_) => match treat_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => { - Some(SimplifiedType::Placeholder) - } + TreatParams::ForLookup => Some(SimplifiedType::Placeholder), TreatParams::AsCandidateKey => None, }, ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. - // - // We will have to be careful with lazy normalization here. - // FIXME(lazy_normalization): This is probably not right... + // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` + // when the new solver is enabled by default. TreatParams::ForLookup if !ty.has_non_region_infer() => { Some(SimplifiedType::Placeholder) } - TreatParams::NextSolverLookup => Some(SimplifiedType::Placeholder), TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), @@ -331,7 +304,7 @@ impl DeepRejectCtxt { // Depending on the value of `treat_obligation_params`, we either // treat generic parameters like placeholders or like inference variables. ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::ForLookup => false, TreatParams::AsCandidateKey => true, }, @@ -373,7 +346,7 @@ impl DeepRejectCtxt { let k = impl_ct.kind(); match obligation_ct.kind() { ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::ForLookup => false, TreatParams::AsCandidateKey => true, }, diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 19cef927faf53..de2c01c304612 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,7 +11,9 @@ use rustc_ast_ir::walk_visitable_list; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; +use rustc_macros::{ + Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, +}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index e984f54370178..6bf2051d67ccd 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -3,6 +3,7 @@ use crate::ty::{EarlyBinder, GenericArgsRef}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; @@ -263,7 +264,7 @@ impl<'tcx> Generics { /// Returns the `GenericParamDef` associated with this `EarlyParamRegion`. pub fn region_param( &'tcx self, - param: &ty::EarlyParamRegion, + param: ty::EarlyParamRegion, tcx: TyCtxt<'tcx>, ) -> &'tcx GenericParamDef { let param = self.param_at(param.index as usize, tcx); @@ -274,7 +275,7 @@ impl<'tcx> Generics { } /// Returns the `GenericParamDef` associated with this `ParamTy`. - pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { + pub fn type_param(&'tcx self, param: ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Type { .. } => param, @@ -286,7 +287,7 @@ impl<'tcx> Generics { /// `Generics`. pub fn opt_type_param( &'tcx self, - param: &ParamTy, + param: ParamTy, tcx: TyCtxt<'tcx>, ) -> Option<&'tcx GenericParamDef> { let param = self.opt_param_at(param.index as usize, tcx)?; @@ -297,7 +298,7 @@ impl<'tcx> Generics { } /// Returns the `GenericParamDef` associated with this `ParamConst`. - pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { + pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Const { .. } => param, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index c571ac507248d..e3eea83ba49ad 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -1,3 +1,4 @@ +use rustc_macros::HashStable; use smallvec::SmallVec; use crate::ty::context::TyCtxt; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f8f59fbeab449..a08fde976bc1a 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -8,7 +8,9 @@ use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::FiniteBitSet; -use rustc_macros::HashStable; +use rustc_macros::{ + Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable, TypeVisitable, +}; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Symbol; @@ -168,6 +170,12 @@ pub enum InstanceDef<'tcx> { /// /// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`. FnPtrAddrShim(DefId, Ty<'tcx>), + + /// `core::future::async_drop::async_drop_in_place::<'_, T>`. + /// + /// The `DefId` is for `core::future::async_drop::async_drop_in_place`, the `Ty` + /// is the type `T`. + AsyncDropGlueCtorShim(DefId, Option>), } impl<'tcx> Instance<'tcx> { @@ -210,7 +218,9 @@ impl<'tcx> Instance<'tcx> { InstanceDef::Item(def) => tcx .upstream_monomorphizations_for(def) .and_then(|monos| monos.get(&self.args).cloned()), - InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args), + InstanceDef::DropGlue(_, Some(_)) | InstanceDef::AsyncDropGlueCtorShim(_, _) => { + tcx.upstream_drop_glue_for(self.args) + } _ => None, } } @@ -235,7 +245,8 @@ impl<'tcx> InstanceDef<'tcx> { | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) - | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, + | InstanceDef::FnPtrAddrShim(def_id, _) + | InstanceDef::AsyncDropGlueCtorShim(def_id, _) => def_id, } } @@ -243,9 +254,9 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { match self { ty::InstanceDef::Item(def) => Some(def), - ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => { - Some(def_id) - } + ty::InstanceDef::DropGlue(def_id, Some(_)) + | InstanceDef::AsyncDropGlueCtorShim(def_id, _) + | InstanceDef::ThreadLocalShim(def_id) => Some(def_id), InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) @@ -279,6 +290,7 @@ impl<'tcx> InstanceDef<'tcx> { let def_id = match *self { ty::InstanceDef::Item(def) => def, ty::InstanceDef::DropGlue(_, Some(_)) => return false, + ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => return false, ty::InstanceDef::ThreadLocalShim(_) => return false, _ => return true, }; @@ -347,11 +359,13 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::ThreadLocalShim(..) | InstanceDef::FnPtrAddrShim(..) | InstanceDef::FnPtrShim(..) - | InstanceDef::DropGlue(_, Some(_)) => false, + | InstanceDef::DropGlue(_, Some(_)) + | InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) + | InstanceDef::AsyncDropGlueCtorShim(..) | InstanceDef::Item(_) | InstanceDef::Intrinsic(..) | InstanceDef::ReifyShim(..) @@ -396,6 +410,8 @@ fn fmt_instance( InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), + InstanceDef::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"), + InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), } } @@ -638,6 +654,12 @@ impl<'tcx> Instance<'tcx> { Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) } + pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { + let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); + let args = tcx.mk_args(&[ty.into()]); + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + } + #[instrument(level = "debug", skip(tcx), ret)] pub fn fn_once_adapter_instance( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs index 18d08ed23a5e5..68c1d8c17ec11 100644 --- a/compiler/rustc_middle/src/ty/intrinsic.rs +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -1,3 +1,4 @@ +use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{def_id::DefId, Symbol}; use super::TyCtxt; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6381bd190ac0a..f8490e5e15fc0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -10,6 +10,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_session::config::OptLevel; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; @@ -124,7 +125,7 @@ impl Primitive { F64 => tcx.types.f64, F128 => tcx.types.f128, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Pointer(_) => Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)), + Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit), } } @@ -338,6 +339,10 @@ impl<'tcx> SizeSkeleton<'tcx> { debug_assert!(tail.has_non_region_param()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } + ty::Error(guar) => { + // Fixes ICE #124031 + return Err(tcx.arena.alloc(LayoutError::ReferencesError(*guar))); + } _ => bug!( "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \ tail `{tail}` is not a type parameter or a projection", @@ -770,7 +775,7 @@ where // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { - let nil = Ty::new_unit(tcx); + let nil = tcx.types.unit; let unit_ptr_ty = if this.ty.is_unsafe_ptr() { Ty::new_mut_ptr(tcx, nil) } else { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d0a69c6fd2c1f..73b20f0485b6e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -45,16 +45,18 @@ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_index::IndexVec; -use rustc_macros::HashStable; +use rustc_macros::{ + Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, +}; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{hygiene, ExpnId, ExpnKind, Span}; +use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -224,8 +226,15 @@ pub struct ResolverAstLowering { pub lint_buffer: Steal, /// Information about functions signatures for delegation items expansion - pub has_self: LocalDefIdSet, - pub fn_parameter_counts: LocalDefIdMap, + pub delegation_fn_sigs: LocalDefIdMap, +} + +#[derive(Debug)] +pub struct DelegationFnSig { + pub header: ast::FnHeader, + pub param_count: usize, + pub has_self: bool, + pub c_variadic: bool, } #[derive(Clone, Copy, Debug)] @@ -1076,7 +1085,7 @@ struct ParamTag { reveal: traits::Reveal, } -impl_tag! { +rustc_data_structures::impl_tag! { impl Tag for ParamTag; ParamTag { reveal: traits::Reveal::UserFacing }, ParamTag { reveal: traits::Reveal::All }, @@ -1215,7 +1224,7 @@ pub struct Destructor { #[derive(Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub struct VariantFlags(u8); -bitflags! { +bitflags::bitflags! { impl VariantFlags: u8 { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. @@ -1494,14 +1503,14 @@ pub enum ImplOverlapKind { /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait marker: bool, }, - /// These impls are allowed to overlap, but that raises - /// an issue #33140 future-compatibility warning. + /// These impls are allowed to overlap, but that raises an + /// issue #33140 future-compatibility warning (tracked in #56484). /// /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different. /// - /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied - /// that difference, making what reduces to the following set of impls: + /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied on + /// that difference, doing what reduces to the following set of impls: /// /// ```compile_fail,(E0119) /// trait Trait {} @@ -1526,7 +1535,7 @@ pub enum ImplOverlapKind { /// 4. Neither of the impls can have any where-clauses. /// /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed. - Issue33140, + FutureCompatOrderDepTraitObjects, } /// Useful source information about where a desugared associated type for an @@ -1721,27 +1730,26 @@ impl<'tcx> TyCtxt<'tcx> { | (ImplPolarity::Negative, ImplPolarity::Negative) => {} }; - let is_marker_overlap = { - let is_marker_impl = - |trait_ref: TraitRef<'_>| -> bool { self.trait_def(trait_ref.def_id).is_marker }; - is_marker_impl(trait_ref1) && is_marker_impl(trait_ref2) - }; + let is_marker_impl = |trait_ref: TraitRef<'_>| self.trait_def(trait_ref.def_id).is_marker; + let is_marker_overlap = is_marker_impl(trait_ref1) && is_marker_impl(trait_ref2); if is_marker_overlap { - Some(ImplOverlapKind::Permitted { marker: true }) - } else { - if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { - if let Some(self_ty2) = self.issue33140_self_ty(def_id2) { - if self_ty1 == self_ty2 { - return Some(ImplOverlapKind::Issue33140); - } else { - debug!("found {self_ty1:?} != {self_ty2:?}"); - } - } - } + return Some(ImplOverlapKind::Permitted { marker: true }); + } - None + if let Some(self_ty1) = + self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id1) + && let Some(self_ty2) = + self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id2) + { + if self_ty1 == self_ty2 { + return Some(ImplOverlapKind::FutureCompatOrderDepTraitObjects); + } else { + debug!("found {self_ty1:?} != {self_ty2:?}"); + } } + + None } /// Returns `ty::VariantDef` if `res` refers to a struct, @@ -1797,7 +1805,8 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance), + | ty::InstanceDef::FnPtrAddrShim(..) + | ty::InstanceDef::AsyncDropGlueCtorShim(..) => self.mir_shims(instance), } } @@ -2005,22 +2014,6 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } - /// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost - /// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled). - /// Only applies when `Span` is the result of macro expansion. - /// - /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default - /// and only when a (some enclosing) macro definition is annotated with `#[collapse_debuginfo]`. - /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. - /// - /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. - pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span { - if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() { - return span; - } - hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo) - } - #[inline] pub fn is_const_fn_raw(self, def_id: DefId) -> bool { matches!( diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 5854367446022..791f27a97896d 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -10,6 +10,7 @@ use crate::traits::query::NoSolution; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; use crate::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)] pub enum NormalizationError<'tcx> { diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 8a41ba257ec63..d1875fbaea376 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -2,6 +2,7 @@ use std::fmt; use crate::ty; use rustc_data_structures::intern::Interned; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 05156dd5205e7..56dd52567fde0 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -3,6 +3,7 @@ use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; +use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; use rustc_type_ir::ClauseKind as IrClauseKind; use rustc_type_ir::PredicateKind as IrPredicateKind; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0bd009cd51da1..5f47aef0f32cb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,6 +16,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathDataName}; use rustc_hir::LangItem; +use rustc_macros::Lift; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_session::Limit; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -1276,7 +1277,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn pretty_print_inherent_projection( &mut self, - alias_ty: &ty::AliasTy<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> Result<(), PrintError> { let def_key = self.tcx().def_key(alias_ty.def_id); self.path_generic_args( @@ -3204,7 +3205,7 @@ define_print_and_forward_display! { ty::AliasTy<'tcx> { if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) { - p!(pretty_print_inherent_projection(self)) + p!(pretty_print_inherent_projection(*self)) } else { // If we're printing verbosely, or don't want to invoke queries // (`is_impl_trait_in_trait`), then fall back to printing the def path. diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index b92800a172880..3d9be15310fee 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -3,6 +3,7 @@ use rustc_data_structures::intern::Interned; use rustc_errors::MultiSpan; use rustc_hir::def_id::DefId; use rustc_index::Idx; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::symbol::sym; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3c1dea1d9f249..7063ef07201bb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -10,6 +10,7 @@ use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_macros::TypeVisitable; use rustc_target::spec::abi; use std::iter; diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index 17eabec257e93..cb2f7284eaa0d 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -1,6 +1,7 @@ use crate::middle::region::{Scope, ScopeData, ScopeTree}; use rustc_hir as hir; use rustc_hir::ItemLocalMap; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by /// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6084e8d7cab2a..de70c4f7b65a1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -17,13 +17,14 @@ use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; +use std::iter; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; @@ -1379,7 +1380,7 @@ impl<'tcx> ParamTy { Ty::new_param(tcx, self.index, self.name) } - pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span { + pub fn span_from_generics(self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span { let generics = tcx.generics_of(item_with_generics); let type_param = generics.type_param(self, tcx); tcx.def_span(type_param.def_id) @@ -1749,11 +1750,6 @@ impl<'tcx> Ty<'tcx> { // misc - #[inline] - pub fn new_unit(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.types.unit - } - #[inline] pub fn new_static_str(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_) @@ -2316,6 +2312,133 @@ impl<'tcx> Ty<'tcx> { } } + /// Returns the type of the async destructor of this type. + pub fn async_destructor_ty(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Ty<'tcx> { + if self.is_async_destructor_noop(tcx, param_env) || matches!(self.kind(), ty::Error(_)) { + return Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop) + .instantiate_identity(); + } + match *self.kind() { + ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { + let assoc_items = tcx + .associated_item_def_ids(tcx.require_lang_item(LangItem::AsyncDestruct, None)); + Ty::new_projection(tcx, assoc_items[0], [self]) + } + + ty::Array(elem_ty, _) | ty::Slice(elem_ty) => { + let dtor = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropSlice) + .instantiate(tcx, &[elem_ty.into()]); + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[dtor.into()]) + } + + ty::Adt(adt_def, args) if adt_def.is_enum() || adt_def.is_struct() => self + .adt_async_destructor_ty( + tcx, + adt_def.variants().iter().map(|v| v.fields.iter().map(|f| f.ty(tcx, args))), + param_env, + ), + ty::Tuple(tys) => self.adt_async_destructor_ty(tcx, iter::once(tys), param_env), + ty::Closure(_, args) => self.adt_async_destructor_ty( + tcx, + iter::once(args.as_closure().upvar_tys()), + param_env, + ), + ty::CoroutineClosure(_, args) => self.adt_async_destructor_ty( + tcx, + iter::once(args.as_coroutine_closure().upvar_tys()), + param_env, + ), + + ty::Adt(adt_def, _) => { + assert!(adt_def.is_union()); + + let surface_drop = self.surface_async_dropper_ty(tcx, param_env).unwrap(); + + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[surface_drop.into()]) + } + + ty::Bound(..) + | ty::Foreign(_) + | ty::Placeholder(_) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("`async_destructor_ty` applied to unexpected type: {self:?}") + } + + _ => bug!("`async_destructor_ty` is not yet implemented for type: {self:?}"), + } + } + + fn adt_async_destructor_ty( + self, + tcx: TyCtxt<'tcx>, + variants: I, + param_env: ParamEnv<'tcx>, + ) -> Ty<'tcx> + where + I: Iterator + ExactSizeIterator, + I::Item: IntoIterator>, + { + debug_assert!(!self.is_async_destructor_noop(tcx, param_env)); + + let defer = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDefer); + let chain = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain); + + let noop = + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity(); + let either = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropEither); + + let variants_dtor = variants + .into_iter() + .map(|variant| { + variant + .into_iter() + .map(|ty| defer.instantiate(tcx, &[ty.into()])) + .reduce(|acc, next| chain.instantiate(tcx, &[acc.into(), next.into()])) + .unwrap_or(noop) + }) + .reduce(|other, matched| { + either.instantiate(tcx, &[other.into(), matched.into(), self.into()]) + }) + .unwrap(); + + let dtor = if let Some(dropper_ty) = self.surface_async_dropper_ty(tcx, param_env) { + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain) + .instantiate(tcx, &[dropper_ty.into(), variants_dtor.into()]) + } else { + variants_dtor + }; + + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[dtor.into()]) + } + + fn surface_async_dropper_ty( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option> { + if self.has_surface_async_drop(tcx, param_env) { + Some(LangItem::SurfaceAsyncDropInPlace) + } else if self.has_surface_drop(tcx, param_env) { + Some(LangItem::AsyncDropSurfaceDropInPlace) + } else { + None + } + .map(|dropper| { + Ty::async_destructor_combinator(tcx, dropper).instantiate(tcx, &[self.into()]) + }) + } + + fn async_destructor_combinator( + tcx: TyCtxt<'tcx>, + lang_item: LangItem, + ) -> ty::EarlyBinder> { + tcx.fn_sig(tcx.require_lang_item(lang_item, None)) + .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) + } + /// Returns the type of metadata for (potentially fat) pointers to this type, /// or the struct tail if the metadata type cannot be determined. pub fn ptr_metadata_ty_or_tail( diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index d85b541d36386..cf5decffea92b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; use crate::ty::{Ident, Ty, TyCtxt}; use hir::def_id::LOCAL_CRATE; use rustc_hir as hir; @@ -8,7 +8,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_macros::HashStable; +use rustc_macros::{Decodable, Encodable, HashStable}; /// A trait's definition with type information. #[derive(HashStable, Encodable, Decodable)] @@ -135,21 +135,6 @@ impl<'tcx> TyCtxt<'tcx> { self, trait_def_id: DefId, self_ty: Ty<'tcx>, - f: impl FnMut(DefId), - ) { - self.for_each_relevant_impl_treating_projections( - trait_def_id, - self_ty, - TreatProjections::ForLookup, - f, - ) - } - - pub fn for_each_relevant_impl_treating_projections( - self, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - treat_projections: TreatProjections, mut f: impl FnMut(DefId), ) { // FIXME: This depends on the set of all impls for the trait. That is @@ -163,17 +148,13 @@ impl<'tcx> TyCtxt<'tcx> { f(impl_def_id); } - // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using - // `TreatParams::AsCandidateKey` while actually adding them. - let treat_params = match treat_projections { - TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, - TreatProjections::ForLookup => TreatParams::ForLookup, - }; // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option`, `Vec`, `ConcreteType` and so on. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using + // `TreatParams::AsCandidateKey` while actually adding them. + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { f(impl_def_id); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index a28afcc4fb8c2..41f417dfd4b1a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -7,10 +7,8 @@ use crate::{ GenericArgs, GenericArgsRef, Ty, UserArgs, }, }; -use rustc_data_structures::{ - fx::FxIndexMap, - unord::{ExtendUnord, UnordItems, UnordSet}, -}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::{ self as hir, @@ -20,7 +18,7 @@ use rustc_hir::{ BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability, }; use rustc_index::IndexVec; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; @@ -201,8 +199,7 @@ pub struct TypeckResults<'tcx> { /// Stores the predicates that apply on coroutine witness types. /// formatting modified file tests/ui/coroutine/retain-resume-ref.rs - pub coroutine_interior_predicates: - LocalDefIdMap, ObligationCause<'tcx>)>>, + pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>, /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. @@ -243,7 +240,7 @@ impl<'tcx> TypeckResults<'tcx> { closure_min_captures: Default::default(), closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), - coroutine_interior_predicates: Default::default(), + coroutine_stalled_predicates: Default::default(), treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), offset_of_data: Default::default(), @@ -451,7 +448,7 @@ impl<'tcx> TypeckResults<'tcx> { /// This is computed from the typeck results since we want to make /// sure to apply any match-ergonomics adjustments, which we cannot /// determine from the HIR alone. - pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool { + pub fn pat_has_ref_mut_binding(&self, pat: &hir::Pat<'_>) -> bool { let mut has_ref_mut = false; pat.walk(|pat| { if let hir::PatKind::Binding(_, id, _, _) = pat.kind diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9af665cfb6fe0..f5e973f85da12 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -17,12 +17,12 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; -use rustc_macros::HashStable; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_session::Limit; use rustc_span::sym; use rustc_target::abi::{Integer, IntegerType, Primitive, Size}; use rustc_target::spec::abi::Abi; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::{fmt, iter}; #[derive(Copy, Clone, Debug)] @@ -432,19 +432,19 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|&(_, k)| { match k.unpack() { GenericArgKind::Lifetime(region) => match region.kind() { - ty::ReEarlyParam(ref ebr) => { + ty::ReEarlyParam(ebr) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } // Error: not a region param _ => false, }, - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(ref pt) => !impl_generics.type_param(pt, self).pure_wrt_drop, + GenericArgKind::Type(ty) => match *ty.kind() { + ty::Param(pt) => !impl_generics.type_param(pt, self).pure_wrt_drop, // Error: not a type param _ => false, }, GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Param(ref pc) => { + ty::ConstKind::Param(pc) => { !impl_generics.const_param(pc, self).pure_wrt_drop } // Error: not a const param @@ -1303,6 +1303,98 @@ impl<'tcx> Ty<'tcx> { } } + /// Checks whether values of this type `T` implements the `AsyncDrop` + /// trait. + pub fn has_surface_async_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.could_have_surface_async_drop() && tcx.has_surface_async_drop_raw(param_env.and(self)) + } + + /// Fast path helper for testing if a type has `AsyncDrop` + /// implementation. + /// + /// Returning `false` means the type is known to not have `AsyncDrop` + /// implementation. Returning `true` means nothing -- could be + /// `AsyncDrop`, might not be. + fn could_have_surface_async_drop(self) -> bool { + !self.is_async_destructor_trivially_noop() + && !matches!( + self.kind(), + ty::Tuple(_) + | ty::Slice(_) + | ty::Array(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + ) + } + + /// Checks whether values of this type `T` implements the `Drop` + /// trait. + pub fn has_surface_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.could_have_surface_drop() && tcx.has_surface_drop_raw(param_env.and(self)) + } + + /// Fast path helper for testing if a type has `Drop` implementation. + /// + /// Returning `false` means the type is known to not have `Drop` + /// implementation. Returning `true` means nothing -- could be + /// `Drop`, might not be. + fn could_have_surface_drop(self) -> bool { + !self.is_async_destructor_trivially_noop() + && !matches!( + self.kind(), + ty::Tuple(_) + | ty::Slice(_) + | ty::Array(_, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + ) + } + + /// Checks whether values of this type `T` implement has noop async destructor. + // + // FIXME: implement optimization to make ADTs, which do not need drop, + // to skip fields or to have noop async destructor. + pub fn is_async_destructor_noop( + self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + self.is_async_destructor_trivially_noop() + || if let ty::Adt(adt_def, _) = self.kind() { + (adt_def.is_union() || adt_def.is_payloadfree()) + && !self.has_surface_async_drop(tcx, param_env) + && !self.has_surface_drop(tcx, param_env) + } else { + false + } + } + + /// Fast path helper for testing if a type has noop async destructor. + /// + /// Returning `true` means the type is known to have noop async destructor + /// implementation. Returning `true` means nothing -- could be + /// `Drop`, might not be. + fn is_async_destructor_trivially_noop(self) -> bool { + match self.kind() { + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Never + | ty::Ref(..) + | ty::RawPtr(..) + | ty::FnDef(..) + | ty::FnPtr(_) => true, + ty::Tuple(tys) => tys.is_empty(), + ty::Adt(adt_def, _) => adt_def.is_manually_drop(), + _ => false, + } + } + /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// `false`, then `ty` definitely has no destructor (i.e., no drop glue). diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 62f41921d888a..2ad194313100a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -3,6 +3,7 @@ use std::fmt; use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; +use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, HashStable)] pub enum VtblEntry<'tcx> { diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 7069bdcbcb984..089e61749c3e8 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -4,7 +4,7 @@ use crate::ty::{self, Ty}; use crate::ty::{GenericArg, GenericArgKind}; use rustc_data_structures::sso::SsoHashSet; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 57f809ef7cf8a..e2a5f97a84744 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -1,30 +1,25 @@ +mod mcdc; use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; -use std::collections::VecDeque; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageKind, MCDCBranchSpan, - MCDCDecisionSpan, -}; -use rustc_middle::mir::{self, BasicBlock, UnOp}; -use rustc_middle::thir::{ExprId, ExprKind, LogicalOp, Thir}; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; +use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; +use rustc_middle::thir::{ExprId, ExprKind, Thir}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; -use rustc_span::Span; -use crate::build::Builder; -use crate::errors::MCDCExceedsConditionNumLimit; +use crate::build::coverageinfo::mcdc::MCDCInfoBuilder; +use crate::build::{Builder, CFG}; pub(crate) struct BranchInfoBuilder { /// Maps condition expressions to their enclosing `!`, for better instrumentation. nots: FxHashMap, - num_block_markers: usize, + markers: BlockMarkerGen, branch_spans: Vec, - mcdc_branch_spans: Vec, - mcdc_decision_spans: Vec, - mcdc_state: Option, + + mcdc_info: Option, } #[derive(Clone, Copy)] @@ -37,6 +32,35 @@ struct NotInfo { is_flipped: bool, } +#[derive(Default)] +struct BlockMarkerGen { + num_block_markers: usize, +} + +impl BlockMarkerGen { + fn next_block_marker_id(&mut self) -> BlockMarkerId { + let id = BlockMarkerId::from_usize(self.num_block_markers); + self.num_block_markers += 1; + id + } + + fn inject_block_marker( + &mut self, + cfg: &mut CFG<'_>, + source_info: SourceInfo, + block: BasicBlock, + ) -> BlockMarkerId { + let id = self.next_block_marker_id(); + let marker_statement = mir::Statement { + source_info, + kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), + }; + cfg.push(block, marker_statement); + + id + } +} + impl BranchInfoBuilder { /// Creates a new branch info builder, but only if branch coverage instrumentation /// is enabled and `def_id` represents a function that is eligible for coverage. @@ -44,11 +68,9 @@ impl BranchInfoBuilder { if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) { Some(Self { nots: FxHashMap::default(), - num_block_markers: 0, + markers: BlockMarkerGen::default(), branch_spans: vec![], - mcdc_branch_spans: vec![], - mcdc_decision_spans: vec![], - mcdc_state: MCDCState::new_if_enabled(tcx), + mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), }) } else { None @@ -95,69 +117,25 @@ impl BranchInfoBuilder { } } - fn record_conditions_operation(&mut self, logical_op: LogicalOp, span: Span) { - if let Some(mcdc_state) = self.mcdc_state.as_mut() { - mcdc_state.record_conditions(logical_op, span); - } - } - - fn fetch_condition_info( + fn add_two_way_branch<'tcx>( &mut self, - tcx: TyCtxt<'_>, - true_marker: BlockMarkerId, - false_marker: BlockMarkerId, - ) -> Option { - let mcdc_state = self.mcdc_state.as_mut()?; - let (mut condition_info, decision_result) = - mcdc_state.take_condition(true_marker, false_marker); - if let Some(decision) = decision_result { - match decision.conditions_num { - 0 => { - unreachable!("Decision with no condition is not expected"); - } - 1..=MAX_CONDITIONS_NUM_IN_DECISION => { - self.mcdc_decision_spans.push(decision); - } - _ => { - // Do not generate mcdc mappings and statements for decisions with too many conditions. - let rebase_idx = self.mcdc_branch_spans.len() - decision.conditions_num + 1; - let to_normal_branches = self.mcdc_branch_spans.split_off(rebase_idx); - self.branch_spans.extend(to_normal_branches.into_iter().map( - |MCDCBranchSpan { span, true_marker, false_marker, .. }| BranchSpan { - span, - true_marker, - false_marker, - }, - )); - - // ConditionInfo of this branch shall also be reset. - condition_info = None; - - tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit { - span: decision.span, - conditions_num: decision.conditions_num, - max_conditions_num: MAX_CONDITIONS_NUM_IN_DECISION, - }); - } - } - } - condition_info - } + cfg: &mut CFG<'tcx>, + source_info: SourceInfo, + true_block: BasicBlock, + false_block: BasicBlock, + ) { + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); + let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); - fn next_block_marker_id(&mut self) -> BlockMarkerId { - let id = BlockMarkerId::from_usize(self.num_block_markers); - self.num_block_markers += 1; - id + self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker }); } pub(crate) fn into_done(self) -> Option> { let Self { nots: _, - num_block_markers, + markers: BlockMarkerGen { num_block_markers }, branch_spans, - mcdc_branch_spans, - mcdc_decision_spans, - .. + mcdc_info, } = self; if num_block_markers == 0 { @@ -165,6 +143,9 @@ impl BranchInfoBuilder { return None; } + let (mcdc_decision_spans, mcdc_branch_spans) = + mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); + Some(Box::new(mir::coverage::BranchInfo { num_block_markers, branch_spans, @@ -174,147 +155,6 @@ impl BranchInfoBuilder { } } -/// The MCDC bitmap scales exponentially (2^n) based on the number of conditions seen, -/// So llvm sets a maximum value prevents the bitmap footprint from growing too large without the user's knowledge. -/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged. -const MAX_CONDITIONS_NUM_IN_DECISION: usize = 6; - -struct MCDCState { - /// To construct condition evaluation tree. - decision_stack: VecDeque, - processing_decision: Option, -} - -impl MCDCState { - fn new_if_enabled(tcx: TyCtxt<'_>) -> Option { - tcx.sess - .instrument_coverage_mcdc() - .then(|| Self { decision_stack: VecDeque::new(), processing_decision: None }) - } - - // At first we assign ConditionIds for each sub expression. - // If the sub expression is composite, re-assign its ConditionId to its LHS and generate a new ConditionId for its RHS. - // - // Example: "x = (A && B) || (C && D) || (D && F)" - // - // Visit Depth1: - // (A && B) || (C && D) || (D && F) - // ^-------LHS--------^ ^-RHS--^ - // ID=1 ID=2 - // - // Visit LHS-Depth2: - // (A && B) || (C && D) - // ^-LHS--^ ^-RHS--^ - // ID=1 ID=3 - // - // Visit LHS-Depth3: - // (A && B) - // LHS RHS - // ID=1 ID=4 - // - // Visit RHS-Depth3: - // (C && D) - // LHS RHS - // ID=3 ID=5 - // - // Visit RHS-Depth2: (D && F) - // LHS RHS - // ID=2 ID=6 - // - // Visit Depth1: - // (A && B) || (C && D) || (D && F) - // ID=1 ID=4 ID=3 ID=5 ID=2 ID=6 - // - // A node ID of '0' always means MC/DC isn't being tracked. - // - // If a "next" node ID is '0', it means it's the end of the test vector. - // - // As the compiler tracks expression in pre-order, we can ensure that condition info of parents are always properly assigned when their children are visited. - // - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next". - // - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next". - fn record_conditions(&mut self, op: LogicalOp, span: Span) { - let decision = match self.processing_decision.as_mut() { - Some(decision) => { - decision.span = decision.span.to(span); - decision - } - None => self.processing_decision.insert(MCDCDecisionSpan { - span, - conditions_num: 0, - end_markers: vec![], - }), - }; - - let parent_condition = self.decision_stack.pop_back().unwrap_or_default(); - let lhs_id = if parent_condition.condition_id == ConditionId::NONE { - decision.conditions_num += 1; - ConditionId::from(decision.conditions_num) - } else { - parent_condition.condition_id - }; - - decision.conditions_num += 1; - let rhs_condition_id = ConditionId::from(decision.conditions_num); - - let (lhs, rhs) = match op { - LogicalOp::And => { - let lhs = ConditionInfo { - condition_id: lhs_id, - true_next_id: rhs_condition_id, - false_next_id: parent_condition.false_next_id, - }; - let rhs = ConditionInfo { - condition_id: rhs_condition_id, - true_next_id: parent_condition.true_next_id, - false_next_id: parent_condition.false_next_id, - }; - (lhs, rhs) - } - LogicalOp::Or => { - let lhs = ConditionInfo { - condition_id: lhs_id, - true_next_id: parent_condition.true_next_id, - false_next_id: rhs_condition_id, - }; - let rhs = ConditionInfo { - condition_id: rhs_condition_id, - true_next_id: parent_condition.true_next_id, - false_next_id: parent_condition.false_next_id, - }; - (lhs, rhs) - } - }; - // We visit expressions tree in pre-order, so place the left-hand side on the top. - self.decision_stack.push_back(rhs); - self.decision_stack.push_back(lhs); - } - - fn take_condition( - &mut self, - true_marker: BlockMarkerId, - false_marker: BlockMarkerId, - ) -> (Option, Option) { - let Some(condition_info) = self.decision_stack.pop_back() else { - return (None, None); - }; - let Some(decision) = self.processing_decision.as_mut() else { - bug!("Processing decision should have been created before any conditions are taken"); - }; - if condition_info.true_next_id == ConditionId::NONE { - decision.end_markers.push(true_marker); - } - if condition_info.false_next_id == ConditionId::NONE { - decision.end_markers.push(false_marker); - } - - if self.decision_stack.is_empty() { - (Some(condition_info), self.processing_decision.take()) - } else { - (Some(condition_info), None) - } - } -} - impl Builder<'_, '_> { /// If branch coverage is enabled, inject marker statements into `then_block` /// and `else_block`, and record their IDs in the table of branch spans. @@ -325,7 +165,7 @@ impl Builder<'_, '_> { mut else_block: BasicBlock, ) { // Bail out if branch coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_ref() else { return }; + let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; // If this condition expression is nested within one or more `!` expressions, // replace it with the enclosing `!` collected by `visit_unary_not`. @@ -335,47 +175,24 @@ impl Builder<'_, '_> { std::mem::swap(&mut then_block, &mut else_block); } } - let source_info = self.source_info(self.thir[expr_id].span); - - // Now that we have `source_info`, we can upgrade to a &mut reference. - let branch_info = self.coverage_branch_info.as_mut().expect("upgrading & to &mut"); - let mut inject_branch_marker = |block: BasicBlock| { - let id = branch_info.next_block_marker_id(); + let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; - let marker_statement = mir::Statement { - source_info, - kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), + // Separate path for handling branches when MC/DC is enabled. + if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() { + let inject_block_marker = |source_info, block| { + branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block) }; - self.cfg.push(block, marker_statement); - - id - }; - - let true_marker = inject_branch_marker(then_block); - let false_marker = inject_branch_marker(else_block); - - if let Some(condition_info) = - branch_info.fetch_condition_info(self.tcx, true_marker, false_marker) - { - branch_info.mcdc_branch_spans.push(MCDCBranchSpan { - span: source_info.span, - condition_info, - true_marker, - false_marker, - }); - } else { - branch_info.branch_spans.push(BranchSpan { - span: source_info.span, - true_marker, - false_marker, - }); + mcdc_info.visit_evaluated_condition( + self.tcx, + source_info, + then_block, + else_block, + inject_block_marker, + ); + return; } - } - pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() { - branch_info.record_conditions_operation(logical_op, span); - } + branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block); } } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs new file mode 100644 index 0000000000000..566dba460d43b --- /dev/null +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -0,0 +1,275 @@ +use std::collections::VecDeque; + +use rustc_middle::mir::coverage::{ + BlockMarkerId, ConditionId, ConditionInfo, MCDCBranchSpan, MCDCDecisionSpan, +}; +use rustc_middle::mir::{BasicBlock, SourceInfo}; +use rustc_middle::thir::LogicalOp; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +use crate::build::Builder; +use crate::errors::MCDCExceedsConditionNumLimit; + +/// The MCDC bitmap scales exponentially (2^n) based on the number of conditions seen, +/// So llvm sets a maximum value prevents the bitmap footprint from growing too large without the user's knowledge. +/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged. +const MAX_CONDITIONS_NUM_IN_DECISION: usize = 6; + +#[derive(Default)] +struct MCDCDecisionCtx { + /// To construct condition evaluation tree. + decision_stack: VecDeque, + processing_decision: Option, +} + +struct MCDCState { + decision_ctx_stack: Vec, +} + +impl MCDCState { + fn new() -> Self { + Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] } + } + + /// Decision depth is given as a u16 to reduce the size of the `CoverageKind`, + /// as it is very unlikely that the depth ever reaches 2^16. + #[inline] + fn decision_depth(&self) -> u16 { + match u16::try_from(self.decision_ctx_stack.len()) + .expect( + "decision depth did not fit in u16, this is likely to be an instrumentation error", + ) + .checked_sub(1) + { + Some(d) => d, + None => bug!("Unexpected empty decision stack"), + } + } + + // At first we assign ConditionIds for each sub expression. + // If the sub expression is composite, re-assign its ConditionId to its LHS and generate a new ConditionId for its RHS. + // + // Example: "x = (A && B) || (C && D) || (D && F)" + // + // Visit Depth1: + // (A && B) || (C && D) || (D && F) + // ^-------LHS--------^ ^-RHS--^ + // ID=1 ID=2 + // + // Visit LHS-Depth2: + // (A && B) || (C && D) + // ^-LHS--^ ^-RHS--^ + // ID=1 ID=3 + // + // Visit LHS-Depth3: + // (A && B) + // LHS RHS + // ID=1 ID=4 + // + // Visit RHS-Depth3: + // (C && D) + // LHS RHS + // ID=3 ID=5 + // + // Visit RHS-Depth2: (D && F) + // LHS RHS + // ID=2 ID=6 + // + // Visit Depth1: + // (A && B) || (C && D) || (D && F) + // ID=1 ID=4 ID=3 ID=5 ID=2 ID=6 + // + // A node ID of '0' always means MC/DC isn't being tracked. + // + // If a "next" node ID is '0', it means it's the end of the test vector. + // + // As the compiler tracks expression in pre-order, we can ensure that condition info of parents are always properly assigned when their children are visited. + // - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next". + // - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next". + fn record_conditions(&mut self, op: LogicalOp, span: Span) { + let decision_depth = self.decision_depth(); + let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { + bug!("Unexpected empty decision_ctx_stack") + }; + let decision = match decision_ctx.processing_decision.as_mut() { + Some(decision) => { + decision.span = decision.span.to(span); + decision + } + None => decision_ctx.processing_decision.insert(MCDCDecisionSpan { + span, + conditions_num: 0, + end_markers: vec![], + decision_depth, + }), + }; + + let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_default(); + let lhs_id = if parent_condition.condition_id == ConditionId::NONE { + decision.conditions_num += 1; + ConditionId::from(decision.conditions_num) + } else { + parent_condition.condition_id + }; + + decision.conditions_num += 1; + let rhs_condition_id = ConditionId::from(decision.conditions_num); + + let (lhs, rhs) = match op { + LogicalOp::And => { + let lhs = ConditionInfo { + condition_id: lhs_id, + true_next_id: rhs_condition_id, + false_next_id: parent_condition.false_next_id, + }; + let rhs = ConditionInfo { + condition_id: rhs_condition_id, + true_next_id: parent_condition.true_next_id, + false_next_id: parent_condition.false_next_id, + }; + (lhs, rhs) + } + LogicalOp::Or => { + let lhs = ConditionInfo { + condition_id: lhs_id, + true_next_id: parent_condition.true_next_id, + false_next_id: rhs_condition_id, + }; + let rhs = ConditionInfo { + condition_id: rhs_condition_id, + true_next_id: parent_condition.true_next_id, + false_next_id: parent_condition.false_next_id, + }; + (lhs, rhs) + } + }; + // We visit expressions tree in pre-order, so place the left-hand side on the top. + decision_ctx.decision_stack.push_back(rhs); + decision_ctx.decision_stack.push_back(lhs); + } + + fn take_condition( + &mut self, + true_marker: BlockMarkerId, + false_marker: BlockMarkerId, + ) -> (Option, Option) { + let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { + bug!("Unexpected empty decision_ctx_stack") + }; + let Some(condition_info) = decision_ctx.decision_stack.pop_back() else { + return (None, None); + }; + let Some(decision) = decision_ctx.processing_decision.as_mut() else { + bug!("Processing decision should have been created before any conditions are taken"); + }; + if condition_info.true_next_id == ConditionId::NONE { + decision.end_markers.push(true_marker); + } + if condition_info.false_next_id == ConditionId::NONE { + decision.end_markers.push(false_marker); + } + + if decision_ctx.decision_stack.is_empty() { + (Some(condition_info), decision_ctx.processing_decision.take()) + } else { + (Some(condition_info), None) + } + } +} + +pub struct MCDCInfoBuilder { + branch_spans: Vec, + decision_spans: Vec, + state: MCDCState, +} + +impl MCDCInfoBuilder { + pub fn new() -> Self { + Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() } + } + + pub fn visit_evaluated_condition( + &mut self, + tcx: TyCtxt<'_>, + source_info: SourceInfo, + true_block: BasicBlock, + false_block: BasicBlock, + mut inject_block_marker: impl FnMut(SourceInfo, BasicBlock) -> BlockMarkerId, + ) { + let true_marker = inject_block_marker(source_info, true_block); + let false_marker = inject_block_marker(source_info, false_block); + + let decision_depth = self.state.decision_depth(); + let (mut condition_info, decision_result) = + self.state.take_condition(true_marker, false_marker); + // take_condition() returns Some for decision_result when the decision stack + // is empty, i.e. when all the conditions of the decision were instrumented, + // and the decision is "complete". + if let Some(decision) = decision_result { + match decision.conditions_num { + 0 => { + unreachable!("Decision with no condition is not expected"); + } + 1..=MAX_CONDITIONS_NUM_IN_DECISION => { + self.decision_spans.push(decision); + } + _ => { + // Do not generate mcdc mappings and statements for decisions with too many conditions. + let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1; + for branch in &mut self.branch_spans[rebase_idx..] { + branch.condition_info = None; + } + + // ConditionInfo of this branch shall also be reset. + condition_info = None; + + tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit { + span: decision.span, + conditions_num: decision.conditions_num, + max_conditions_num: MAX_CONDITIONS_NUM_IN_DECISION, + }); + } + } + } + self.branch_spans.push(MCDCBranchSpan { + span: source_info.span, + condition_info, + true_marker, + false_marker, + decision_depth, + }); + } + + pub fn into_done(self) -> (Vec, Vec) { + (self.decision_spans, self.branch_spans) + } +} + +impl Builder<'_, '_> { + pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) { + if let Some(branch_info) = self.coverage_branch_info.as_mut() + && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + { + mcdc_info.state.record_conditions(logical_op, span); + } + } + + pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) { + if let Some(branch_info) = self.coverage_branch_info.as_mut() + && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + { + mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default()); + }; + } + + pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { + if let Some(branch_info) = self.coverage_branch_info.as_mut() + && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + { + if mcdc_info.state.decision_ctx_stack.pop().is_none() { + bug!("Unexpected empty decision stack"); + } + }; + } +} diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index f12e25db6fcd5..060b328ef48ae 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -685,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temp.into(), Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Fake, + BorrowKind::Fake(FakeBorrowKind::Shallow), Place { local: base_place.local, projection }, ), ); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f46dceeeedf58..bce1526775963 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -10,10 +10,7 @@ use crate::build::scope::DropKind; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; -use rustc_data_structures::{ - fx::{FxHashSet, FxIndexMap, FxIndexSet}, - stack::ensure_sufficient_stack, -}; +use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack}; use rustc_hir::{BindingMode, ByRef}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; @@ -76,14 +73,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; match expr.kind { - ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { - this.visit_coverage_branch_operation(LogicalOp::And, expr_span); + ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => { + this.visit_coverage_branch_operation(op, expr_span); let lhs_then_block = unpack!(this.then_else_break_inner(block, lhs, args)); let rhs_then_block = unpack!(this.then_else_break_inner(lhs_then_block, rhs, args)); rhs_then_block.unit() } - ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => { - this.visit_coverage_branch_operation(LogicalOp::Or, expr_span); + ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => { + this.visit_coverage_branch_operation(op, expr_span); let local_scope = this.local_scope(); let (lhs_success_block, failure_block) = this.in_if_then_scope(local_scope, expr_span, |this| { @@ -151,8 +148,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut block = block; let temp_scope = args.temp_scope_override.unwrap_or_else(|| this.local_scope()); let mutability = Mutability::Mut; + + // Increment the decision depth, in case we encounter boolean expressions + // further down. + this.mcdc_increment_depth_if_enabled(); let place = unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability)); + this.mcdc_decrement_depth_if_enabled(); + let operand = Operand::Move(Place::from(place)); let then_block = this.cfg.start_new_block(); @@ -211,7 +214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 2. Create the decision tree ([Builder::lower_match_tree]). /// 3. Determine the fake borrows that are needed from the places that were /// matched against and create the required temporaries for them - /// ([Builder::calculate_fake_borrows]). + /// ([util::collect_fake_borrows]). /// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]). /// /// ## False edges @@ -380,12 +383,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_start_span: Span, match_has_guard: bool, candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) -> Vec<(Place<'tcx>, Local)> { - // The set of places that we are creating fake borrows of. If there are - // no match guards then we don't need any fake borrows, so don't track - // them. - let fake_borrows = match_has_guard - .then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates)); + ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { + // The set of places that we are creating fake borrows of. If there are no match guards then + // we don't need any fake borrows, so don't track them. + let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { + util::collect_fake_borrows( + self, + candidates, + scrutinee_span, + scrutinee_place_builder.base(), + ) + } else { + Vec::new() + }; // See the doc comment on `match_candidates` for why we have an // otherwise block. Match checking will ensure this is actually @@ -439,11 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); } - if let Some(ref borrows) = fake_borrows { - self.calculate_fake_borrows(borrows, scrutinee_span) - } else { - Vec::new() - } + fake_borrows } /// Lower the bindings, guards and arm bodies of a `match` expression. @@ -459,7 +465,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, ) -> BlockAnd<()> { let arm_end_blocks: Vec<_> = arm_candidates .into_iter() @@ -543,7 +549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, - fake_borrow_temps: &[(Place<'tcx>, Local)], + fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, storages_alive: bool, @@ -940,7 +946,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); } - PatKind::DerefPattern { ref subpattern } => { + PatKind::DerefPattern { ref subpattern, .. } => { self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); } @@ -1165,6 +1171,7 @@ enum TestCase<'pat, 'tcx> { Constant { value: mir::Const<'tcx> }, Range(&'pat PatRange<'tcx>), Slice { len: usize, variable_length: bool }, + Deref { temp: Place<'tcx>, mutability: Mutability }, Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, } @@ -1224,6 +1231,13 @@ enum TestKind<'tcx> { /// Test that the length of the slice is equal to `len`. Len { len: u64, op: BinOp }, + + /// Call `Deref::deref[_mut]` on the value. + Deref { + /// Temporary to store the result of `deref()`/`deref_mut()`. + temp: Place<'tcx>, + mutability: Mutability, + }, } /// A test to perform to determine which [`Candidate`] matches a value. @@ -1905,81 +1919,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target_blocks, ); } - - /// Determine the fake borrows that are needed from a set of places that - /// have to be stable across match guards. - /// - /// Returns a list of places that need a fake borrow and the temporary - /// that's used to store the fake borrow. - /// - /// Match exhaustiveness checking is not able to handle the case where the - /// place being matched on is mutated in the guards. We add "fake borrows" - /// to the guards that prevent any mutation of the place being matched. - /// There are a some subtleties: - /// - /// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared - /// reference, the borrow isn't even tracked. As such we have to add fake - /// borrows of any prefixes of a place - /// 2. We don't want `match x { _ => (), }` to conflict with mutable - /// borrows of `x`, so we only add fake borrows for places which are - /// bound or tested by the match. - /// 3. We don't want the fake borrows to conflict with `ref mut` bindings, - /// so we use a special BorrowKind for them. - /// 4. The fake borrows may be of places in inactive variants, so it would - /// be UB to generate code for them. They therefore have to be removed - /// by a MIR pass run after borrow checking. - fn calculate_fake_borrows<'b>( - &mut self, - fake_borrows: &'b FxIndexSet>, - temp_span: Span, - ) -> Vec<(Place<'tcx>, Local)> { - let tcx = self.tcx; - - debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); - - let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len()); - - // Insert a Shallow borrow of the prefixes of any fake borrows. - for place in fake_borrows { - let mut cursor = place.projection.as_ref(); - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - - if let ProjectionElem::Deref = elem { - // Insert a shallow borrow after a deref. For other - // projections the borrow of prefix_cursor will - // conflict with any mutation of base. - all_fake_borrows.push(PlaceRef { local: place.local, projection: proj_base }); - } - } - - all_fake_borrows.push(place.as_ref()); - } - - // Deduplicate - let mut dedup = FxHashSet::default(); - all_fake_borrows.retain(|b| dedup.insert(*b)); - - debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); - - all_fake_borrows - .into_iter() - .map(|matched_place_ref| { - let matched_place = Place { - local: matched_place_ref.local, - projection: tcx.mk_place_elems(matched_place_ref.projection), - }; - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; - let fake_borrow_ty = - Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); - let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); - fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); - let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); - - (matched_place, fake_borrow_temp) - }) - .collect() - } } /////////////////////////////////////////////////////////////////////////// @@ -2044,7 +1983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, parent_data: &[PatternExtraData<'tcx>], - fake_borrows: &[(Place<'tcx>, Local)], + fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: bool, @@ -2174,8 +2113,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let re_erased = tcx.lifetimes.re_erased; let scrutinee_source_info = self.source_info(scrutinee_span); - for &(place, temp) in fake_borrows { - let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake, place); + for &(place, temp, kind) in fake_borrows { + let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake(kind), place); self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } @@ -2198,7 +2137,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let guard_frame = self.guard_context.pop().unwrap(); debug!("Exiting guard building context with locals: {:?}", guard_frame); - for &(_, temp) in fake_borrows { + for &(_, temp, _) in fake_borrows { let cause = FakeReadCause::ForMatchGuard; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 690879b94885a..5dd478aa4224a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -42,6 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Len { len: len as u64, op } } + TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability }, + TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Irrefutable { .. } => span_bug!( @@ -143,34 +145,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } let re_erased = tcx.lifetimes.re_erased; - let ref_string = self.temp(Ty::new_imm_ref(tcx, re_erased, ty), test.span); let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); - let deref = tcx.require_lang_item(LangItem::Deref, None); - let method = trait_method(tcx, deref, sym::deref, [ty]); let eq_block = self.cfg.start_new_block(); - self.cfg.push_assign( - block, - source_info, - ref_string, - Rvalue::Ref(re_erased, BorrowKind::Shared, place), - ); - self.cfg.terminate( + // `let ref_str: &str = ::deref(&place);` + self.call_deref( block, - source_info, - TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span: test.span, - user_ty: None, - const_: method, - })), - args: vec![Spanned { node: Operand::Move(ref_string), span: DUMMY_SP }], - destination: ref_str, - target: Some(eq_block), - unwind: UnwindAction::Continue, - call_source: CallSource::Misc, - fn_span: source_info.span, - }, + eq_block, + place, + Mutability::Not, + ty, + ref_str, + test.span, ); self.non_scalar_compare( eq_block, @@ -270,9 +256,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Operand::Move(expected), ); } + + TestKind::Deref { temp, mutability } => { + let ty = place_ty.ty; + let target = target_block(TestBranch::Success); + self.call_deref(block, target, place, mutability, ty, temp, test.span); + } } } + /// Perform `let temp = ::deref(&place)`. + /// or `let temp = ::deref_mut(&mut place)`. + pub(super) fn call_deref( + &mut self, + block: BasicBlock, + target_block: BasicBlock, + place: Place<'tcx>, + mutability: Mutability, + ty: Ty<'tcx>, + temp: Place<'tcx>, + span: Span, + ) { + let (trait_item, method) = match mutability { + Mutability::Not => (LangItem::Deref, sym::deref), + Mutability::Mut => (LangItem::DerefMut, sym::deref_mut), + }; + let borrow_kind = super::util::ref_pat_borrow_kind(mutability); + let source_info = self.source_info(span); + let re_erased = self.tcx.lifetimes.re_erased; + let trait_item = self.tcx.require_lang_item(trait_item, None); + let method = trait_method(self.tcx, trait_item, method, [ty]); + let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span); + // `let ref_src = &src_place;` + // or `let ref_src = &mut src_place;` + self.cfg.push_assign( + block, + source_info, + ref_src, + Rvalue::Ref(re_erased, borrow_kind, place), + ); + // `let temp = ::deref(ref_src);` + // or `let temp = ::deref_mut(ref_src);` + self.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { + span, + user_ty: None, + const_: method, + })), + args: vec![Spanned { node: Operand::Move(ref_src), span }], + destination: temp, + target: Some(target_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: source_info.span, + }, + ); + } + /// Compare using the provided built-in comparison operator fn compare( &mut self, @@ -660,13 +703,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. }) + if test_temp == temp => + { + fully_matched = true; + Some(TestBranch::Success) + } + ( TestKind::Switch { .. } | TestKind::SwitchInt { .. } | TestKind::If | TestKind::Len { .. } | TestKind::Range { .. } - | TestKind::Eq { .. }, + | TestKind::Eq { .. } + | TestKind::Deref { .. }, _, ) => { fully_matched = false; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d6376b7b0dcac..2f9390c22a89d 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,12 +1,13 @@ use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; -use rustc_middle::ty; use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn field_match_pairs<'pat>( @@ -249,10 +250,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { default_irrefutable() } - PatKind::DerefPattern { .. } => { - // FIXME(deref_patterns) - // Treat it like a wildcard for now. - default_irrefutable() + PatKind::DerefPattern { ref subpattern, mutability } => { + // Create a new temporary for each deref pattern. + // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? + let temp = cx.temp( + Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), + pattern.span, + ); + subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); + TestCase::Deref { temp, mutability } } }; @@ -262,19 +268,103 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { cx: &'a mut Builder<'b, 'tcx>, - fake_borrows: FxIndexSet>, + /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from + /// bindings inside deref patterns. + scrutinee_base: PlaceBase, + /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest + /// borrow (i.e. Deep > Shallow). + /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are + /// dereferences are also borrowed with the same of stronger borrow kind. + fake_borrows: FxIndexMap, FakeBorrowKind>, +} + +/// Determine the set of places that have to be stable across match guards. +/// +/// Returns a list of places that need a fake borrow along with a local to store it. +/// +/// Match exhaustiveness checking is not able to handle the case where the place being matched on is +/// mutated in the guards. We add "fake borrows" to the guards that prevent any mutation of the +/// place being matched. There are a some subtleties: +/// +/// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared reference, the borrow +/// isn't even tracked. As such we have to add fake borrows of any prefixes of a place. +/// 2. We don't want `match x { (Some(_), _) => (), .. }` to conflict with mutable borrows of `x.1`, so we +/// only add fake borrows for places which are bound or tested by the match. +/// 3. We don't want `match x { Some(_) => (), .. }` to conflict with mutable borrows of `(x as +/// Some).0`, so the borrows are a special shallow borrow that only affects the place and not its +/// projections. +/// ```rust +/// let mut x = (Some(0), true); +/// match x { +/// (Some(_), false) => {} +/// _ if { if let Some(ref mut y) = x.0 { *y += 1 }; true } => {} +/// _ => {} +/// } +/// ``` +/// 4. The fake borrows may be of places in inactive variants, e.g. here we need to fake borrow `x` +/// and `(x as Some).0`, but when we reach the guard `x` may not be `Some`. +/// ```rust +/// let mut x = (Some(Some(0)), true); +/// match x { +/// (Some(Some(_)), false) => {} +/// _ if { if let Some(Some(ref mut y)) = x.0 { *y += 1 }; true } => {} +/// _ => {} +/// } +/// ``` +/// So it would be UB to generate code for the fake borrows. They therefore have to be removed by +/// a MIR pass run after borrow checking. +pub(super) fn collect_fake_borrows<'tcx>( + cx: &mut Builder<'_, 'tcx>, + candidates: &[&mut Candidate<'_, 'tcx>], + temp_span: Span, + scrutinee_base: PlaceBase, +) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { + let mut collector = + FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() }; + for candidate in candidates.iter() { + collector.visit_candidate(candidate); + } + let fake_borrows = collector.fake_borrows; + debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); + let tcx = cx.tcx; + fake_borrows + .iter() + .map(|(matched_place, borrow_kind)| { + let fake_borrow_deref_ty = matched_place.ty(&cx.local_decls, tcx).ty; + let fake_borrow_ty = + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); + let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); + fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); + let fake_borrow_temp = cx.local_decls.push(fake_borrow_temp); + (*matched_place, fake_borrow_temp, *borrow_kind) + }) + .collect() } impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { - pub(super) fn collect_fake_borrows( - cx: &'a mut Builder<'b, 'tcx>, - candidates: &[&mut Candidate<'_, 'tcx>], - ) -> FxIndexSet> { - let mut collector = Self { cx, fake_borrows: FxIndexSet::default() }; - for candidate in candidates.iter() { - collector.visit_candidate(candidate); + // Fake borrow this place and its dereference prefixes. + fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { + if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) { + return; + } + self.fake_borrows.insert(place, kind); + // Also fake borrow the prefixes of any fake borrow. + self.fake_borrow_deref_prefixes(place, kind); + } + + // Fake borrow the prefixes of this place that are dereferences. + fn fake_borrow_deref_prefixes(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { + for (place_ref, elem) in place.as_ref().iter_projections().rev() { + if let ProjectionElem::Deref = elem { + // Insert a shallow borrow after a deref. For other projections the borrow of + // `place_ref` will conflict with any mutation of `place.base`. + let place = place_ref.to_place(self.cx.tcx); + if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) { + return; + } + self.fake_borrows.insert(place, kind); + } } - collector.fake_borrows } fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { @@ -300,10 +390,27 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { for flat_pat in pats.iter() { self.visit_flat_pat(flat_pat) } + } else if matches!(match_pair.test_case, TestCase::Deref { .. }) { + // The subpairs of a deref pattern are all places relative to the deref temporary, so we + // don't fake borrow them. Problem is, if we only shallowly fake-borrowed + // `match_pair.place`, this would allow: + // ``` + // let mut b = Box::new(false); + // match b { + // deref!(true) => {} // not reached because `*b == false` + // _ if { *b = true; false } => {} // not reached because the guard is `false` + // deref!(false) => {} // not reached because the guard changed it + // // UB because we reached the unreachable. + // } + // ``` + // Hence we fake borrow using a deep borrow. + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Deep); + } } else { // Insert a Shallow borrow of any place that is switched on. if let Some(place) = match_pair.place { - self.fake_borrows.insert(place); + self.fake_borrow(place, FakeBorrowKind::Shallow); } for subpair in &match_pair.subpairs { @@ -313,6 +420,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) { + if let PlaceBase::Local(l) = self.scrutinee_base + && l != source.local + { + // The base of this place is a temporary created for deref patterns. We don't emit fake + // borrows for these as they are not initialized in all branches. + return; + } + // Insert a borrows of prefixes of places that are bound and are // behind a dereference projection. // @@ -329,13 +444,13 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // y if { y == 1 && (x = &2) == () } => y, // _ => 3, // } - if let Some(i) = source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) { - let proj_base = &source.projection[..i]; - self.fake_borrows.insert(Place { - local: source.local, - projection: self.cx.tcx.mk_place_elems(proj_base), - }); - } + // + // We don't just fake borrow the whole place because this is allowed: + // match u { + // _ if { u = true; false } => (), + // x => (), + // } + self.fake_borrow_deref_prefixes(*source, FakeBorrowKind::Shallow); } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3c18afe1a78ec..d6e6cc957b4be 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -997,7 +997,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match self.unit_temp { Some(tmp) => tmp, None => { - let ty = Ty::new_unit(self.tcx); + let ty = self.tcx.types.unit; let fn_span = self.fn_span; let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0c1e1d59c4f3f..227d19c3e43c5 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -513,7 +513,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Fake | BorrowKind::Shared + BorrowKind::Fake(_) | BorrowKind::Shared if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) @@ -521,7 +521,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { BorrowKind::Mut { .. } => { self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) } - BorrowKind::Fake | BorrowKind::Shared => {} + BorrowKind::Fake(_) | BorrowKind::Shared => {} } } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 9ddfb12bf7643..f67113afd6d9d 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -423,7 +423,7 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); @@ -871,7 +871,7 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 442f5fa7d172b..e79e3b887fb43 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,7 +5,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index f4f591d15b933..79738b5403548 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -15,7 +15,7 @@ use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::thir::*; -use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; pub(crate) fn thir_body( tcx: TyCtxt<'_>, @@ -39,7 +39,7 @@ pub(crate) fn thir_body( // It will always be `()` in this case. if tcx.is_coroutine(owner_def.to_def_id()) && body.params.is_empty() { cx.thir.params.push(Param { - ty: Ty::new_unit(tcx), + ty: tcx.types.unit, pat: None, ty_span: None, self_kind: None, 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 241d38f90d29b..25ab904670618 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -10,9 +10,7 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; @@ -24,7 +22,6 @@ use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; -use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::{sym, Span}; @@ -64,10 +61,6 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err visitor.error } -fn create_e0004(sess: &Session, sp: Span, error_message: String) -> Diag<'_> { - struct_span_code_err!(sess.dcx(), sp, E0004, "{}", &error_message) -} - #[derive(Debug, Copy, Clone, PartialEq)] enum RefutableFlag { Irrefutable, @@ -975,10 +968,11 @@ fn report_non_exhaustive_match<'p, 'tcx>( // FIXME: migration of this diagnostic will require list support let joined_patterns = joined_uncovered_patterns(cx, &witnesses); - let mut err = create_e0004( - cx.tcx.sess, + let mut err = struct_span_code_err!( + cx.tcx.dcx(), sp, - format!("non-exhaustive patterns: {joined_patterns} not covered"), + E0004, + "non-exhaustive patterns: {joined_patterns} not covered" ); err.span_label( sp, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index bcb43a0054709..5c016682d8d2d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -264,7 +264,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Deref(subpattern) => { - PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) } + let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability } } hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 49e48427b6555..619bfbcf43d3a 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::DerefPattern { subpattern } => { + PatKind::DerefPattern { subpattern, .. } => { print_indented!(self, "DerefPattern { ", depth_lvl + 1); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index d63db6ea8edd8..185e87baed8cf 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -2,6 +2,7 @@ use rustc_hir::lang_items::LangItem; use rustc_index::Idx; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; +use rustc_middle::span_bug; use rustc_middle::traits::Reveal; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::GenericArgsRef; @@ -630,7 +631,7 @@ where let ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty); let ref_place = self.new_temp(ref_ty); - let unit_temp = Place::from(self.new_temp(Ty::new_unit(tcx))); + let unit_temp = Place::from(self.new_temp(tcx.types.unit)); let result = BasicBlockData { statements: vec![self.assign( diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 44a7dcc82775b..ea9cf6565e7c8 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -13,6 +13,7 @@ use rustc_data_structures::work_queue::WorkQueue; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; +use rustc_middle::bug; use rustc_middle::mir::{self, traversal, BasicBlock}; use rustc_middle::mir::{create_dump_file, dump_enabled}; use rustc_middle::ty::print::with_no_trimmed_paths; diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 693994b5da76f..bdc70de58e84b 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -102,7 +102,7 @@ where } Rvalue::Cast(..) - | Rvalue::Ref(_, BorrowKind::Fake, _) + | Rvalue::Ref(_, BorrowKind::Fake(_), _) | Rvalue::ShallowInitBox(..) | Rvalue::Use(..) | Rvalue::ThreadLocalRef(..) diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 720515f262db8..180168c731686 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,5 +1,6 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::Idx; +use rustc_middle::bug; use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index c5adb81b614ce..5e96a73f6c53f 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -6,8 +6,6 @@ #[macro_use] extern crate tracing; -#[macro_use] -extern crate rustc_middle; use rustc_middle::ty; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index d7477309400b6..6ae7df79d3094 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -2,6 +2,7 @@ use rustc_index::IndexVec; use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::{bug, span_bug}; use smallvec::{smallvec, SmallVec}; use std::mem; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 22cf3999239c1..830f44df5fb39 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -358,20 +358,15 @@ impl<'tcx> MoveData<'tcx> { builder::gather_moves(body, tcx, param_env, filter) } - /// For the move path `mpi`, returns the root local variable (if any) that starts the path. - /// (e.g., for a path like `a.b.c` returns `Some(a)`) - pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { + /// For the move path `mpi`, returns the root local variable that starts the path. + /// (e.g., for a path like `a.b.c` returns `a`) + pub fn base_local(&self, mut mpi: MovePathIndex) -> Local { loop { let path = &self.move_paths[mpi]; if let Some(l) = path.place.as_local() { - return Some(l); - } - if let Some(parent) = path.parent { - mpi = parent; - continue; - } else { - return None; + return l; } + mpi = path.parent.expect("root move paths should be locals"); } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 0e85f859ab2c2..807bef0741178 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -40,6 +40,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; +use rustc_middle::bug; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index da82f8de78147..48a6a83e14609 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -29,7 +29,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { for statement in basic_block.statements.iter_mut() { match statement.kind { StatementKind::AscribeUserType(..) - | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _))) + | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake(_), _))) | StatementKind::Coverage( // These kinds of coverage statements are markers inserted during // MIR building, and are not needed after InstrumentCoverage. diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index e2a911f0dc7d9..3008016863e4c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -80,6 +80,10 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::PanicStrategy; +use rustc_trait_selection::infer::TyCtxtInferExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use std::{iter, ops}; pub struct StateTransform; @@ -1256,7 +1260,7 @@ fn create_coroutine_drop_shim<'tcx>( } // Replace the return variable - body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(Ty::new_unit(tcx), source_info); + body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.types.unit, source_info); make_coroutine_state_argument_indirect(tcx, &mut body); @@ -1584,10 +1588,46 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>( let (_, coroutine_layout, _) = compute_layout(liveness_info, body); check_suspend_tys(tcx, &coroutine_layout, body); + check_field_tys_sized(tcx, &coroutine_layout, def_id); Some(coroutine_layout) } +fn check_field_tys_sized<'tcx>( + tcx: TyCtxt<'tcx>, + coroutine_layout: &CoroutineLayout<'tcx>, + def_id: LocalDefId, +) { + // No need to check if unsized_locals/unsized_fn_params is disabled, + // since we will error during typeck. + if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params { + return; + } + + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let param_env = tcx.param_env(def_id); + + let ocx = ObligationCtxt::new(&infcx); + for field_ty in &coroutine_layout.field_tys { + ocx.register_bound( + ObligationCause::new( + field_ty.source_info.span, + def_id, + ObligationCauseCode::SizedCoroutineInterior(def_id), + ), + param_env, + field_ty.ty, + tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), + ); + } + + let errors = ocx.select_all_or_error(); + debug!(?errors); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(errors); + } +} + impl<'tcx> MirPass<'tcx> for StateTransform { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Some(old_yield_ty) = body.yield_ty() else { diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs new file mode 100644 index 0000000000000..d364658efb6d6 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -0,0 +1,275 @@ +use std::collections::BTreeSet; + +use rustc_data_structures::graph::DirectedGraph; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::coverage::{ + BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind, MCDCBranchSpan, MCDCDecisionSpan, +}; +use rustc_middle::mir::{self, BasicBlock, StatementKind}; +use rustc_span::Span; + +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use crate::coverage::spans::{ + extract_refined_covspans, unexpand_into_body_span_with_visible_macro, +}; +use crate::coverage::ExtractedHirInfo; +use rustc_index::IndexVec; + +#[derive(Clone, Debug)] +pub(super) enum BcbMappingKind { + /// Associates an ordinary executable code span with its corresponding BCB. + Code(BasicCoverageBlock), + + // Ordinary branch mappings are stored separately, so they don't have a + // variant in this enum. + // + /// Associates a mcdc branch span with condition info besides fields for normal branch. + MCDCBranch { + true_bcb: BasicCoverageBlock, + false_bcb: BasicCoverageBlock, + /// If `None`, this actually represents a normal branch mapping inserted + /// for code that was too complex for MC/DC. + condition_info: Option, + decision_depth: u16, + }, + /// Associates a mcdc decision with its join BCB. + MCDCDecision { + end_bcbs: BTreeSet, + bitmap_idx: u32, + conditions_num: u16, + decision_depth: u16, + }, +} + +#[derive(Debug)] +pub(super) struct BcbMapping { + pub(super) kind: BcbMappingKind, + pub(super) span: Span, +} + +/// This is separate from [`BcbMappingKind`] to help prepare for larger changes +/// that will be needed for improved branch coverage in the future. +/// (See .) +#[derive(Debug)] +pub(super) struct BcbBranchPair { + pub(super) span: Span, + pub(super) true_bcb: BasicCoverageBlock, + pub(super) false_bcb: BasicCoverageBlock, +} + +pub(super) struct CoverageSpans { + bcb_has_mappings: BitSet, + pub(super) mappings: Vec, + pub(super) branch_pairs: Vec, + test_vector_bitmap_bytes: u32, +} + +impl CoverageSpans { + pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { + self.bcb_has_mappings.contains(bcb) + } + + pub(super) fn test_vector_bitmap_bytes(&self) -> u32 { + self.test_vector_bitmap_bytes + } +} + +/// Extracts coverage-relevant spans from MIR, and associates them with +/// their corresponding BCBs. +/// +/// Returns `None` if no coverage-relevant spans could be extracted. +pub(super) fn generate_coverage_spans( + mir_body: &mir::Body<'_>, + hir_info: &ExtractedHirInfo, + basic_coverage_blocks: &CoverageGraph, +) -> Option { + let mut mappings = vec![]; + let mut branch_pairs = vec![]; + + if hir_info.is_async_fn { + // An async function desugars into a function that returns a future, + // with the user code wrapped in a closure. Any spans in the desugared + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + if let Some(span) = hir_info.fn_sig_span_extended { + mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span }); + } + } else { + extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut mappings); + + branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); + + mappings.extend(extract_mcdc_mappings(mir_body, hir_info.body_span, basic_coverage_blocks)); + } + + if mappings.is_empty() && branch_pairs.is_empty() { + return None; + } + + // Identify which BCBs have one or more mappings. + let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut insert = |bcb| { + bcb_has_mappings.insert(bcb); + }; + let mut test_vector_bitmap_bytes = 0; + for BcbMapping { kind, span: _ } in &mappings { + match *kind { + BcbMappingKind::Code(bcb) => insert(bcb), + BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => { + insert(true_bcb); + insert(false_bcb); + } + BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => { + // `bcb_has_mappings` is used for inject coverage counters + // but they are not needed for decision BCBs. + // While the length of test vector bitmap should be calculated here. + test_vector_bitmap_bytes = test_vector_bitmap_bytes + .max(bitmap_idx + (1_u32 << conditions_num as u32).div_ceil(8)); + } + } + } + for &BcbBranchPair { true_bcb, false_bcb, .. } in &branch_pairs { + insert(true_bcb); + insert(false_bcb); + } + + Some(CoverageSpans { bcb_has_mappings, mappings, branch_pairs, test_vector_bitmap_bytes }) +} + +fn resolve_block_markers( + branch_info: &mir::coverage::BranchInfo, + mir_body: &mir::Body<'_>, +) -> IndexVec> { + let mut block_markers = IndexVec::>::from_elem_n( + None, + branch_info.num_block_markers, + ); + + // Fill out the mapping from block marker IDs to their enclosing blocks. + for (bb, data) in mir_body.basic_blocks.iter_enumerated() { + for statement in &data.statements { + if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind { + block_markers[id] = Some(bb); + } + } + } + + block_markers +} + +// FIXME: There is currently a lot of redundancy between +// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so +// that they can each be modified without interfering with the other, but in +// the long term we should try to bring them together again when branch coverage +// and MC/DC coverage support are more mature. + +pub(super) fn extract_branch_pairs( + mir_body: &mir::Body<'_>, + hir_info: &ExtractedHirInfo, + basic_coverage_blocks: &CoverageGraph, +) -> Vec { + let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] }; + + let block_markers = resolve_block_markers(branch_info, mir_body); + + branch_info + .branch_spans + .iter() + .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { + // For now, ignore any branch span that was introduced by + // expansion. This makes things like assert macros less noisy. + if !raw_span.ctxt().outer_expn_data().is_root() { + return None; + } + let (span, _) = + unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?; + + let bcb_from_marker = + |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); + + let true_bcb = bcb_from_marker(true_marker)?; + let false_bcb = bcb_from_marker(false_marker)?; + + Some(BcbBranchPair { span, true_bcb, false_bcb }) + }) + .collect::>() +} + +pub(super) fn extract_mcdc_mappings( + mir_body: &mir::Body<'_>, + body_span: Span, + basic_coverage_blocks: &CoverageGraph, +) -> Vec { + let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { + return vec![]; + }; + + let block_markers = resolve_block_markers(branch_info, mir_body); + + let bcb_from_marker = + |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); + + let check_branch_bcb = + |raw_span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId| { + // For now, ignore any branch span that was introduced by + // expansion. This makes things like assert macros less noisy. + if !raw_span.ctxt().outer_expn_data().is_root() { + return None; + } + let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?; + + let true_bcb = bcb_from_marker(true_marker)?; + let false_bcb = bcb_from_marker(false_marker)?; + Some((span, true_bcb, false_bcb)) + }; + + let mcdc_branch_filter_map = |&MCDCBranchSpan { + span: raw_span, + true_marker, + false_marker, + condition_info, + decision_depth, + }| { + check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| { + BcbMapping { + kind: BcbMappingKind::MCDCBranch { + true_bcb, + false_bcb, + condition_info, + decision_depth, + }, + span, + } + }) + }; + + let mut next_bitmap_idx = 0; + + let decision_filter_map = |decision: &MCDCDecisionSpan| { + let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; + + let end_bcbs = decision + .end_markers + .iter() + .map(|&marker| bcb_from_marker(marker)) + .collect::>()?; + + let bitmap_idx = next_bitmap_idx; + next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8); + + Some(BcbMapping { + kind: BcbMappingKind::MCDCDecision { + end_bcbs, + bitmap_idx, + conditions_num: decision.conditions_num as u16, + decision_depth: decision.decision_depth, + }, + span, + }) + }; + + std::iter::empty() + .chain(branch_info.mcdc_branch_spans.iter().filter_map(mcdc_branch_filter_map)) + .chain(branch_info.mcdc_decision_spans.iter().filter_map(decision_filter_map)) + .collect::>() +} diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 9e8648b0f930d..9edde6662469e 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -2,14 +2,14 @@ pub mod query; mod counters; mod graph; +mod mappings; mod spans; - #[cfg(test)] mod tests; use self::counters::{CounterIncrementSite, CoverageCounters}; use self::graph::{BasicCoverageBlock, CoverageGraph}; -use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans}; +use self::mappings::{BcbBranchPair, BcbMapping, BcbMappingKind, CoverageSpans}; use crate::MirPass; @@ -71,7 +71,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Compute coverage spans from the `CoverageGraph`. let Some(coverage_spans) = - spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) + mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) else { // No relevant spans were found in MIR, so skip instrumenting this function. return; @@ -102,12 +102,23 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans); + let mcdc_max_decision_depth = coverage_spans + .mappings + .iter() + .filter_map(|bcb_mapping| match bcb_mapping.kind { + BcbMappingKind::MCDCDecision { decision_depth, .. } => Some(decision_depth), + _ => None, + }) + .max() + .unwrap_or(0); + mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(), expressions: coverage_counters.into_expressions(), mappings, + mcdc_max_decision_depth, })); } @@ -141,21 +152,26 @@ fn create_mappings<'tcx>( let mut mappings = Vec::new(); - mappings.extend(coverage_spans.all_bcb_mappings().filter_map( + mappings.extend(coverage_spans.mappings.iter().filter_map( |BcbMapping { kind: bcb_mapping_kind, span }| { let kind = match *bcb_mapping_kind { BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), - BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch { + BcbMappingKind::MCDCBranch { + true_bcb, false_bcb, condition_info: None, .. + } => MappingKind::Branch { true_term: term_for_bcb(true_bcb), false_term: term_for_bcb(false_bcb), }, - BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => { - MappingKind::MCDCBranch { - true_term: term_for_bcb(true_bcb), - false_term: term_for_bcb(false_bcb), - mcdc_params: condition_info, - } - } + BcbMappingKind::MCDCBranch { + true_bcb, + false_bcb, + condition_info: Some(mcdc_params), + .. + } => MappingKind::MCDCBranch { + true_term: term_for_bcb(true_bcb), + false_term: term_for_bcb(false_bcb), + mcdc_params, + }, BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => { MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num }) } @@ -165,6 +181,16 @@ fn create_mappings<'tcx>( }, )); + mappings.extend(coverage_spans.branch_pairs.iter().filter_map( + |&BcbBranchPair { span, true_bcb, false_bcb }| { + let true_term = term_for_bcb(true_bcb); + let false_term = term_for_bcb(false_bcb); + let kind = MappingKind::Branch { true_term, false_term }; + let code_region = make_code_region(source_map, file_name, span, body_span)?; + Some(Mapping { kind, code_region }) + }, + )); + mappings } @@ -232,24 +258,28 @@ fn inject_mcdc_statements<'tcx>( } // Inject test vector update first because `inject_statement` always insert new statement at head. - for (end_bcbs, bitmap_idx) in - coverage_spans.all_bcb_mappings().filter_map(|mapping| match &mapping.kind { - BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, .. } => { - Some((end_bcbs, *bitmap_idx)) + for (end_bcbs, bitmap_idx, decision_depth) in + coverage_spans.mappings.iter().filter_map(|mapping| match &mapping.kind { + BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, decision_depth, .. } => { + Some((end_bcbs, *bitmap_idx, *decision_depth)) } _ => None, }) { for end in end_bcbs { let end_bb = basic_coverage_blocks[*end].leader_bb(); - inject_statement(mir_body, CoverageKind::TestVectorBitmapUpdate { bitmap_idx }, end_bb); + inject_statement( + mir_body, + CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth }, + end_bb, + ); } } - for (true_bcb, false_bcb, condition_id) in - coverage_spans.all_bcb_mappings().filter_map(|mapping| match mapping.kind { - BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => { - Some((true_bcb, false_bcb, condition_info.condition_id)) + for (true_bcb, false_bcb, condition_id, decision_depth) in + coverage_spans.mappings.iter().filter_map(|mapping| match mapping.kind { + BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info, decision_depth } => { + Some((true_bcb, false_bcb, condition_info?.condition_id, decision_depth)) } _ => None, }) @@ -257,13 +287,13 @@ fn inject_mcdc_statements<'tcx>( let true_bb = basic_coverage_blocks[true_bcb].leader_bb(); inject_statement( mir_body, - CoverageKind::CondBitmapUpdate { id: condition_id, value: true }, + CoverageKind::CondBitmapUpdate { id: condition_id, value: true, decision_depth }, true_bb, ); let false_bb = basic_coverage_blocks[false_bcb].leader_bb(); inject_statement( mir_body, - CoverageKind::CondBitmapUpdate { id: condition_id, value: false }, + CoverageKind::CondBitmapUpdate { id: condition_id, value: false, decision_depth }, false_bb, ); } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index a4cd8a38c66a2..d6432e2e9d41c 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,125 +1,31 @@ -use rustc_data_structures::graph::DirectedGraph; -use rustc_index::bit_set::BitSet; use rustc_middle::mir; -use rustc_middle::mir::coverage::ConditionInfo; use rustc_span::{BytePos, Span}; -use std::collections::BTreeSet; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::mappings::{BcbMapping, BcbMappingKind}; use crate::coverage::spans::from_mir::SpanFromMir; use crate::coverage::ExtractedHirInfo; mod from_mir; -#[derive(Clone, Debug)] -pub(super) enum BcbMappingKind { - /// Associates an ordinary executable code span with its corresponding BCB. - Code(BasicCoverageBlock), - /// Associates a branch span with BCBs for its true and false arms. - Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock }, - /// Associates a mcdc branch span with condition info besides fields for normal branch. - MCDCBranch { - true_bcb: BasicCoverageBlock, - false_bcb: BasicCoverageBlock, - condition_info: ConditionInfo, - }, - /// Associates a mcdc decision with its join BCB. - MCDCDecision { end_bcbs: BTreeSet, bitmap_idx: u32, conditions_num: u16 }, -} - -#[derive(Debug)] -pub(super) struct BcbMapping { - pub(super) kind: BcbMappingKind, - pub(super) span: Span, -} - -pub(super) struct CoverageSpans { - bcb_has_mappings: BitSet, - mappings: Vec, - test_vector_bitmap_bytes: u32, -} - -impl CoverageSpans { - pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_has_mappings.contains(bcb) - } - - pub(super) fn all_bcb_mappings(&self) -> impl Iterator { - self.mappings.iter() - } - - pub(super) fn test_vector_bitmap_bytes(&self) -> u32 { - self.test_vector_bitmap_bytes - } -} +// FIXME(#124545) It's awkward that we have to re-export this, because it's an +// internal detail of `from_mir` that is also needed when handling branch and +// MC/DC spans. Ideally we would find a more natural home for it. +pub(super) use from_mir::unexpand_into_body_span_with_visible_macro; -/// Extracts coverage-relevant spans from MIR, and associates them with -/// their corresponding BCBs. -/// -/// Returns `None` if no coverage-relevant spans could be extracted. -pub(super) fn generate_coverage_spans( +pub(super) fn extract_refined_covspans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Option { - let mut mappings = vec![]; - - if hir_info.is_async_fn { - // An async function desugars into a function that returns a future, - // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just keep the signature span - // and ignore all of the spans in the MIR body. - if let Some(span) = hir_info.fn_sig_span_extended { - mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span }); - } - } else { - let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( - mir_body, - hir_info, - basic_coverage_blocks, - ); - let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); - mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { - // Each span produced by the generator represents an ordinary code region. - BcbMapping { kind: BcbMappingKind::Code(bcb), span } - })); - - mappings.extend(from_mir::extract_branch_mappings( - mir_body, - hir_info.body_span, - basic_coverage_blocks, - )); - } - - if mappings.is_empty() { - return None; - } - - // Identify which BCBs have one or more mappings. - let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - let mut insert = |bcb| { - bcb_has_mappings.insert(bcb); - }; - let mut test_vector_bitmap_bytes = 0; - for BcbMapping { kind, span: _ } in &mappings { - match *kind { - BcbMappingKind::Code(bcb) => insert(bcb), - BcbMappingKind::Branch { true_bcb, false_bcb } - | BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => { - insert(true_bcb); - insert(false_bcb); - } - BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => { - // `bcb_has_mappings` is used for inject coverage counters - // but they are not needed for decision BCBs. - // While the length of test vector bitmap should be calculated here. - test_vector_bitmap_bytes = test_vector_bitmap_bytes - .max(bitmap_idx + (1_u32 << conditions_num as u32).div_ceil(8)); - } - } - } - - Some(CoverageSpans { bcb_has_mappings, mappings, test_vector_bitmap_bytes }) + mappings: &mut impl Extend, +) { + let sorted_spans = + from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); + let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); + mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { + // Each span produced by the generator represents an ordinary code region. + BcbMapping { kind: BcbMappingKind::Code(bcb), span } + })); } #[derive(Debug)] diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index b9919a2ae884e..4ce37b5defcee 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,11 +1,8 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, CoverageKind, MCDCBranchSpan, MCDCDecisionSpan, -}; +use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ - self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, + self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; @@ -13,7 +10,6 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; -use crate::coverage::spans::{BcbMapping, BcbMappingKind}; use crate::coverage::ExtractedHirInfo; /// Traverses the MIR body to produce an initial collection of coverage-relevant @@ -287,7 +283,7 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { /// /// [^1]Expansions result from Rust syntax including macros, syntactic sugar, /// etc.). -fn unexpand_into_body_span_with_visible_macro( +pub(crate) fn unexpand_into_body_span_with_visible_macro( original_span: Span, body_span: Span, ) -> Option<(Span, Option)> { @@ -365,92 +361,3 @@ impl SpanFromMir { Self { span, visible_macro, bcb, is_hole } } } - -pub(super) fn extract_branch_mappings( - mir_body: &mir::Body<'_>, - body_span: Span, - basic_coverage_blocks: &CoverageGraph, -) -> Vec { - let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { - return vec![]; - }; - - let mut block_markers = IndexVec::>::from_elem_n( - None, - branch_info.num_block_markers, - ); - - // Fill out the mapping from block marker IDs to their enclosing blocks. - for (bb, data) in mir_body.basic_blocks.iter_enumerated() { - for statement in &data.statements { - if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind { - block_markers[id] = Some(bb); - } - } - } - - let bcb_from_marker = - |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); - - let check_branch_bcb = - |raw_span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId| { - // For now, ignore any branch span that was introduced by - // expansion. This makes things like assert macros less noisy. - if !raw_span.ctxt().outer_expn_data().is_root() { - return None; - } - let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?; - - let true_bcb = bcb_from_marker(true_marker)?; - let false_bcb = bcb_from_marker(false_marker)?; - Some((span, true_bcb, false_bcb)) - }; - - let branch_filter_map = |&BranchSpan { span: raw_span, true_marker, false_marker }| { - check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| { - BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span } - }) - }; - - let mcdc_branch_filter_map = - |&MCDCBranchSpan { span: raw_span, true_marker, false_marker, condition_info }| { - check_branch_bcb(raw_span, true_marker, false_marker).map( - |(span, true_bcb, false_bcb)| BcbMapping { - kind: BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info }, - span, - }, - ) - }; - - let mut next_bitmap_idx = 0; - - let decision_filter_map = |decision: &MCDCDecisionSpan| { - let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; - - let end_bcbs = decision - .end_markers - .iter() - .map(|&marker| bcb_from_marker(marker)) - .collect::>()?; - - let bitmap_idx = next_bitmap_idx; - next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8); - - Some(BcbMapping { - kind: BcbMappingKind::MCDCDecision { - end_bcbs, - bitmap_idx, - conditions_num: decision.conditions_num as u16, - }, - span, - }) - }; - - branch_info - .branch_spans - .iter() - .filter_map(branch_filter_map) - .chain(branch_info.mcdc_branch_spans.iter().filter_map(mcdc_branch_filter_map)) - .chain(branch_info.mcdc_decision_spans.iter().filter_map(decision_filter_map)) - .collect::>() -} diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index ca63f5550ae2e..370e930b74098 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -160,7 +160,7 @@ pub fn deduced_param_attrs<'tcx>( return &[]; } - // If the Freeze language item isn't present, then don't bother. + // If the Freeze lang item isn't present, then don't bother. if tcx.lang_items().freeze_trait().is_none() { return &[]; } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 625d8f53939ff..7a3b08f82f619 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -332,7 +332,8 @@ impl<'tcx> Inliner<'tcx> { | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) => return Ok(()), + | InstanceDef::FnPtrAddrShim(..) + | InstanceDef::AsyncDropGlueCtorShim(..) => return Ok(()), } if self.tcx.is_constructor(callee_def_id) { @@ -719,18 +720,12 @@ impl<'tcx> Inliner<'tcx> { kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, }); - // Copy only unevaluated constants from the callee_body into the caller_body. - // Although we are only pushing `ConstKind::Unevaluated` consts to - // `required_consts`, here we may not only have `ConstKind::Unevaluated` - // because we are calling `instantiate_and_normalize_erasing_regions`. - caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter( - |&ct| match ct.const_ { - Const::Ty(_) => { - bug!("should never encounter ty::UnevaluatedConst in `required_consts`") - } - Const::Val(..) | Const::Unevaluated(..) => true, - }, - )); + // Copy required constants from the callee_body into the caller_body. Although we are only + // pushing unevaluated consts to `required_consts`, here they may have been evaluated + // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again. + caller_body.required_consts.extend( + callee_body.required_consts.into_iter().filter(|ct| ct.const_.is_required_const()), + ); // Now that we incorporated the callee's `required_consts`, we can remove the callee from // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does // some extra work here to save the monomorphization collector work later. It helps a lot, @@ -746,8 +741,9 @@ impl<'tcx> Inliner<'tcx> { caller_body.mentioned_items.remove(idx); caller_body.mentioned_items.extend(callee_body.mentioned_items); } else { - // If we can't find the callee, there's no point in adding its items. - // Probably it already got removed by being inlined elsewhere in the same function. + // If we can't find the callee, there's no point in adding its items. Probably it + // already got removed by being inlined elsewhere in the same function, so we already + // took its items. } } @@ -1083,7 +1079,8 @@ fn try_instance_mir<'tcx>( tcx: TyCtxt<'tcx>, instance: InstanceDef<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { - if let ty::InstanceDef::DropGlue(_, Some(ty)) = instance + if let ty::InstanceDef::DropGlue(_, Some(ty)) + | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) = instance && let ty::Adt(def, args) = ty.kind() { let fields = def.all_fields(); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 99c7b616f1b21..8c5f965108bdc 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -94,8 +94,10 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( | InstanceDef::CloneShim(..) => {} // This shim does not call any other functions, thus there can be no recursion. - InstanceDef::FnPtrAddrShim(..) => continue, - InstanceDef::DropGlue(..) => { + InstanceDef::FnPtrAddrShim(..) => { + continue; + } + InstanceDef::DropGlue(..) | InstanceDef::AsyncDropGlueCtorShim(..) => { // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index b8dbf8a759fcc..90c1c7ba63b45 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -583,33 +583,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { val.into() } - Aggregate(ref kind, ref fields) => { - // Do not const prop union fields as they can be - // made to produce values that don't match their - // underlying layout's type (see ICE #121534). - // If the last element of the `Adt` tuple - // is `Some` it indicates the ADT is a union - if let AggregateKind::Adt(_, _, _, _, Some(_)) = **kind { - return None; - }; - Value::Aggregate { - fields: fields - .iter() - .map(|field| { - self.eval_operand(field).map_or(Value::Uninit, Value::Immediate) - }) - .collect(), - variant: match **kind { - AggregateKind::Adt(_, variant, _, _, _) => variant, - AggregateKind::Array(_) - | AggregateKind::Tuple - | AggregateKind::RawPtr(_, _) - | AggregateKind::Closure(_, _) - | AggregateKind::Coroutine(_, _) - | AggregateKind::CoroutineClosure(_, _) => VariantIdx::ZERO, - }, - } - } + Aggregate(ref kind, ref fields) => Value::Aggregate { + fields: fields + .iter() + .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)) + .collect(), + variant: match **kind { + AggregateKind::Adt(_, variant, _, _, _) => variant, + AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::RawPtr(_, _) + | AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::ZERO, + }, + }, Repeat(ref op, n) => { trace!(?op, ?n); @@ -896,13 +884,20 @@ impl CanConstProp { }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { let ty = body.local_decls[local].ty; - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} - // Either the layout fails to compute, then we can't use this local anyway - // or the local is too large, then we don't want to. - _ => { - *val = ConstPropMode::NoPropagation; - continue; + if ty.is_union() { + // Unions are incompatible with the current implementation of + // const prop because Rust has no concept of an active + // variant of a union + *val = ConstPropMode::NoPropagation; + } else { + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} + // Either the layout fails to compute, then we can't use this local anyway + // or the local is too large, then we don't want to. + _ => { + *val = ConstPropMode::NoPropagation; + continue; + } } } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index e477c068229ff..e69c5da757ed4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -4,7 +4,6 @@ #![feature(cow_is_borrowed)] #![feature(decl_macro)] #![feature(impl_trait_in_assoc_type)] -#![feature(inline_const)] #![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] @@ -333,6 +332,8 @@ fn mir_promoted( body.tainted_by_errors = Some(error_reported); } + // Collect `required_consts` *before* promotion, so if there are any consts being promoted + // we still add them to the list in the outer MIR body. let mut required_consts = Vec::new(); let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); for (bb, bb_data) in traversal::reverse_postorder(&body) { diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 8137525a33243..2267a621a834a 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -21,7 +21,7 @@ impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let language_items = tcx.lang_items(); let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else { - // there is no language item to compare to :) + // there is no lang item to compare to :) return; }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 1f4af0ec63dd9..689a547689a2d 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -13,6 +13,7 @@ //! move analysis runs after promotion on broken MIR. use either::{Left, Right}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -175,6 +176,12 @@ fn collect_temps_and_candidates<'tcx>( struct Validator<'a, 'tcx> { ccx: &'a ConstCx<'a, 'tcx>, temps: &'a mut IndexSlice, + /// For backwards compatibility, we are promoting function calls in `const`/`static` + /// initializers. But we want to avoid evaluating code that might panic and that otherwise would + /// not have been evaluated, so we only promote such calls in basic blocks that are guaranteed + /// to execute. In other words, we only promote such calls in basic blocks that are definitely + /// not dead code. Here we cache the result of computing that set of basic blocks. + promotion_safe_blocks: Option>, } impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> { @@ -260,7 +267,9 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_rvalue(rhs) } Right(terminator) => match &terminator.kind { - TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), + TerminatorKind::Call { func, args, .. } => { + self.validate_call(func, args, loc.block) + } TerminatorKind::Yield { .. } => Err(Unpromotable), kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); @@ -384,7 +393,7 @@ impl<'tcx> Validator<'_, 'tcx> { match kind { // Reject these borrow types just to be safe. // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. - BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { return Err(Unpromotable); } @@ -588,29 +597,79 @@ impl<'tcx> Validator<'_, 'tcx> { Ok(()) } + /// Computes the sets of blocks of this MIR that are definitely going to be executed + /// if the function returns successfully. That makes it safe to promote calls in them + /// that might fail. + fn promotion_safe_blocks(body: &mir::Body<'tcx>) -> FxHashSet { + let mut safe_blocks = FxHashSet::default(); + let mut safe_block = START_BLOCK; + loop { + safe_blocks.insert(safe_block); + // Let's see if we can find another safe block. + safe_block = match body.basic_blocks[safe_block].terminator().kind { + TerminatorKind::Goto { target } => target, + TerminatorKind::Call { target: Some(target), .. } + | TerminatorKind::Drop { target, .. } => { + // This calls a function or the destructor. `target` does not get executed if + // the callee loops or panics. But in both cases the const already fails to + // evaluate, so we are fine considering `target` a safe block for promotion. + target + } + TerminatorKind::Assert { target, .. } => { + // Similar to above, we only consider successful execution. + target + } + _ => { + // No next safe block. + break; + } + }; + } + safe_blocks + } + + /// Returns whether the block is "safe" for promotion, which means it cannot be dead code. + /// We use this to avoid promoting operations that can fail in dead code. + fn is_promotion_safe_block(&mut self, block: BasicBlock) -> bool { + let body = self.body; + let safe_blocks = + self.promotion_safe_blocks.get_or_insert_with(|| Self::promotion_safe_blocks(body)); + safe_blocks.contains(&block) + } + fn validate_call( &mut self, callee: &Operand<'tcx>, args: &[Spanned>], + block: BasicBlock, ) -> Result<(), Unpromotable> { + // Validate the operands. If they fail, there's no question -- we cannot promote. + self.validate_operand(callee)?; + for arg in args { + self.validate_operand(&arg.node)?; + } + + // Functions marked `#[rustc_promotable]` are explicitly allowed to be promoted, so we can + // accept them at this point. let fn_ty = callee.ty(self.body, self.tcx); + if let ty::FnDef(def_id, _) = *fn_ty.kind() { + if self.tcx.is_promotable_const_fn(def_id) { + return Ok(()); + } + } - // Inside const/static items, we promote all (eligible) function calls. - // Everywhere else, we require `#[rustc_promotable]` on the callee. - let promote_all_const_fn = matches!( + // Ideally, we'd stop here and reject the rest. + // But for backward compatibility, we have to accept some promotion in const/static + // initializers. Inline consts are explicitly excluded, they are more recent so we have no + // backwards compatibility reason to allow more promotion inside of them. + let promote_all_fn = matches!( self.const_kind, Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false }) ); - if !promote_all_const_fn { - if let ty::FnDef(def_id, _) = *fn_ty.kind() { - // Never promote runtime `const fn` calls of - // functions without `#[rustc_promotable]`. - if !self.tcx.is_promotable_const_fn(def_id) { - return Err(Unpromotable); - } - } + if !promote_all_fn { + return Err(Unpromotable); } - + // Make sure the callee is a `const fn`. let is_const_fn = match *fn_ty.kind() { ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id), _ => false, @@ -618,23 +677,23 @@ impl<'tcx> Validator<'_, 'tcx> { if !is_const_fn { return Err(Unpromotable); } - - self.validate_operand(callee)?; - for arg in args { - self.validate_operand(&arg.node)?; + // The problem is, this may promote calls to functions that panic. + // We don't want to introduce compilation errors if there's a panic in a call in dead code. + // So we ensure that this is not dead code. + if !self.is_promotion_safe_block(block) { + return Err(Unpromotable); } - + // This passed all checks, so let's accept. Ok(()) } } -// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice, candidates: &[Candidate], ) -> Vec { - let mut validator = Validator { ccx, temps }; + let mut validator = Validator { ccx, temps, promotion_safe_blocks: None }; candidates .iter() @@ -653,6 +712,10 @@ struct Promoter<'a, 'tcx> { /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. keep_original: bool, + + /// If true, add the new const (the promoted) to the required_consts of the parent MIR. + /// This is initially false and then set by the visitor when it encounters a `Call` terminator. + add_to_required: bool, } impl<'a, 'tcx> Promoter<'a, 'tcx> { @@ -755,6 +818,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { TerminatorKind::Call { mut func, mut args, call_source: desugar, fn_span, .. } => { + // This promoted involves a function call, so it may fail to evaluate. + // Let's make sure it is added to `required_consts` so that that failure cannot get lost. + self.add_to_required = true; + self.visit_operand(&mut func, loc); for arg in &mut args { self.visit_operand(&mut arg.node, loc); @@ -789,7 +856,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> { let def = self.source.source.def_id(); - let mut rvalue = { + let (mut rvalue, promoted_op) = { let promoted = &mut self.promoted; let promoted_id = Promoted::new(next_promoted_id); let tcx = self.tcx; @@ -799,11 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) }; - Operand::Constant(Box::new(ConstOperand { - span, - user_ty: None, - const_: Const::Unevaluated(uneval, ty), - })) + ConstOperand { span, user_ty: None, const_: Const::Unevaluated(uneval, ty) } }; let blocks = self.source.basic_blocks.as_mut(); @@ -836,22 +899,26 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let promoted_ref = local_decls.push(promoted_ref); assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); + let promoted_operand = promoted_operand(ref_ty, span); let promoted_ref_statement = Statement { source_info: statement.source_info, kind: StatementKind::Assign(Box::new(( Place::from(promoted_ref), - Rvalue::Use(promoted_operand(ref_ty, span)), + Rvalue::Use(Operand::Constant(Box::new(promoted_operand))), ))), }; self.extra_statements.push((loc, promoted_ref_statement)); - Rvalue::Ref( - tcx.lifetimes.re_erased, - *borrow_kind, - Place { - local: mem::replace(&mut place.local, promoted_ref), - projection: List::empty(), - }, + ( + Rvalue::Ref( + tcx.lifetimes.re_erased, + *borrow_kind, + Place { + local: mem::replace(&mut place.local, promoted_ref), + projection: List::empty(), + }, + ), + promoted_operand, ) }; @@ -863,6 +930,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = self.promoted.span; self.assign(RETURN_PLACE, rvalue, span); + + // Now that we did promotion, we know whether we'll want to add this to `required_consts`. + if self.add_to_required { + self.source.required_consts.push(promoted_op); + } + self.promoted } } @@ -878,6 +951,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { *local = self.promote_temp(*local); } } + + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { + if constant.const_.is_required_const() { + self.promoted.required_consts.push(*constant); + } + + // Skipping `super_constant` as the visitor is otherwise only looking for locals. + } } fn promote_candidates<'tcx>( @@ -931,8 +1012,10 @@ fn promote_candidates<'tcx>( temps: &mut temps, extra_statements: &mut extra_statements, keep_original: false, + add_to_required: false, }; + // `required_consts` of the promoted itself gets filled while building the MIR body. let mut promoted = promoter.promote_candidate(candidate, promotions.len()); promoted.source.promoted = Some(promotions.next_index()); promotions.push(promoted); diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index abde6a47e83aa..71ac929d35ebd 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,6 +1,5 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Const, ConstOperand, Location}; -use rustc_middle::ty::ConstKind; +use rustc_middle::mir::{ConstOperand, Location}; pub struct RequiredConstsVisitor<'a, 'tcx> { required_consts: &'a mut Vec>, @@ -14,14 +13,8 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) { - let const_ = constant.const_; - match const_ { - Const::Ty(c) => match c.kind() { - ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {} - _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c), - }, - Const::Unevaluated(..) => self.required_consts.push(*constant), - Const::Val(..) => {} + if constant.const_.is_required_const() { + self.required_consts.push(*constant); } } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index fa6906bdd554f..1c85a604053c7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -22,6 +22,8 @@ use crate::{ use rustc_middle::mir::patch::MirPatch; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; +mod async_destructor_ctor; + pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } @@ -127,6 +129,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), + ty::InstanceDef::AsyncDropGlueCtorShim(def_id, ty) => { + async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty) + } ty::InstanceDef::Virtual(..) => { bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) } diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs new file mode 100644 index 0000000000000..80eadb9abdcf4 --- /dev/null +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -0,0 +1,618 @@ +use std::iter; + +use itertools::Itertools; +use rustc_ast::Mutability; +use rustc_const_eval::interpret; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Body, CallSource, CastKind, Const, ConstOperand, ConstValue, Local, + LocalDecl, MirSource, Operand, Place, PlaceElem, Rvalue, SourceInfo, Statement, StatementKind, + Terminator, TerminatorKind, UnwindAction, UnwindTerminateReason, RETURN_PLACE, +}; +use rustc_middle::ty::adjustment::PointerCoercion; +use rustc_middle::ty::util::Discr; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::source_map::respan; +use rustc_span::{Span, Symbol}; +use rustc_target::abi::{FieldIdx, VariantIdx}; +use rustc_target::spec::PanicStrategy; + +use super::{local_decls_for_sig, new_body}; + +pub fn build_async_destructor_ctor_shim<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + ty: Option>, +) -> Body<'tcx> { + debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); + + AsyncDestructorCtorShimBuilder::new(tcx, def_id, ty).build() +} + +/// Builder for async_drop_in_place shim. Functions as a stack machine +/// to build up an expression using combinators. Stack contains pairs +/// of locals and types. Combinator is a not yet instantiated pair of a +/// function and a type, is considered to be an operator which consumes +/// operands from the stack by instantiating its function and its type +/// with operand types and moving locals into the function call. Top +/// pair is considered to be the last operand. +// FIXME: add mir-opt tests +struct AsyncDestructorCtorShimBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + self_ty: Option>, + span: Span, + source_info: SourceInfo, + param_env: ty::ParamEnv<'tcx>, + + stack: Vec>, + last_bb: BasicBlock, + top_cleanup_bb: Option, + + locals: IndexVec>, + bbs: IndexVec>, +} + +#[derive(Clone, Copy)] +enum SurfaceDropKind { + Async, + Sync, +} + +impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { + const SELF_PTR: Local = Local::from_u32(1); + const INPUT_COUNT: usize = 1; + const MAX_STACK_LEN: usize = 2; + + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Option>) -> Self { + let args = if let Some(ty) = self_ty { + tcx.mk_args(&[ty.into()]) + } else { + ty::GenericArgs::identity_for_item(tcx, def_id) + }; + let sig = tcx.fn_sig(def_id).instantiate(tcx, args); + let sig = tcx.instantiate_bound_regions_with_erased(sig); + let span = tcx.def_span(def_id); + + let source_info = SourceInfo::outermost(span); + + debug_assert_eq!(sig.inputs().len(), Self::INPUT_COUNT); + let locals = local_decls_for_sig(&sig, span); + + // Usual case: noop() + unwind resume + return + let mut bbs = IndexVec::with_capacity(3); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + AsyncDestructorCtorShimBuilder { + tcx, + def_id, + self_ty, + span, + source_info, + param_env, + + stack: Vec::with_capacity(Self::MAX_STACK_LEN), + last_bb: bbs.push(BasicBlockData::new(None)), + top_cleanup_bb: match tcx.sess.panic_strategy() { + PanicStrategy::Unwind => { + // Don't drop input arg because it's just a pointer + Some(bbs.push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::UnwindResume, + }), + is_cleanup: true, + })) + } + PanicStrategy::Abort => None, + }, + + locals, + bbs, + } + } + + fn build(self) -> Body<'tcx> { + let (tcx, def_id, Some(self_ty)) = (self.tcx, self.def_id, self.self_ty) else { + return self.build_zst_output(); + }; + + let surface_drop_kind = || { + let param_env = tcx.param_env_reveal_all_normalized(def_id); + if self_ty.has_surface_async_drop(tcx, param_env) { + Some(SurfaceDropKind::Async) + } else if self_ty.has_surface_drop(tcx, param_env) { + Some(SurfaceDropKind::Sync) + } else { + None + } + }; + + match self_ty.kind() { + ty::Array(elem_ty, _) => self.build_slice(true, *elem_ty), + ty::Slice(elem_ty) => self.build_slice(false, *elem_ty), + + ty::Tuple(elem_tys) => self.build_chain(None, elem_tys.iter()), + ty::Adt(adt_def, args) if adt_def.is_struct() => { + let field_tys = adt_def.non_enum_variant().fields.iter().map(|f| f.ty(tcx, args)); + self.build_chain(surface_drop_kind(), field_tys) + } + ty::Closure(_, args) => self.build_chain(None, args.as_closure().upvar_tys().iter()), + ty::CoroutineClosure(_, args) => { + self.build_chain(None, args.as_coroutine_closure().upvar_tys().iter()) + } + + ty::Adt(adt_def, args) if adt_def.is_enum() => { + self.build_enum(*adt_def, *args, surface_drop_kind()) + } + + ty::Adt(adt_def, _) => { + assert!(adt_def.is_union()); + match surface_drop_kind().unwrap() { + SurfaceDropKind::Async => self.build_fused_async_surface(), + SurfaceDropKind::Sync => self.build_fused_sync_surface(), + } + } + + ty::Bound(..) + | ty::Foreign(_) + | ty::Placeholder(_) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) | ty::TyVar(_)) + | ty::Param(_) + | ty::Alias(..) => { + bug!("Building async destructor for unexpected type: {self_ty:?}") + } + + _ => { + bug!( + "Building async destructor constructor shim is not yet implemented for type: {self_ty:?}" + ) + } + } + } + + fn build_enum( + mut self, + adt_def: ty::AdtDef<'tcx>, + args: ty::GenericArgsRef<'tcx>, + surface_drop: Option, + ) -> Body<'tcx> { + let tcx = self.tcx; + + let surface = match surface_drop { + None => None, + Some(kind) => { + self.put_self(); + Some(match kind { + SurfaceDropKind::Async => self.combine_async_surface(), + SurfaceDropKind::Sync => self.combine_sync_surface(), + }) + } + }; + + let mut other = None; + for (variant_idx, discr) in adt_def.discriminants(tcx) { + let variant = adt_def.variant(variant_idx); + + let mut chain = None; + for (field_idx, field) in variant.fields.iter_enumerated() { + let field_ty = field.ty(tcx, args); + self.put_variant_field(variant.name, variant_idx, field_idx, field_ty); + let defer = self.combine_defer(field_ty); + chain = Some(match chain { + None => defer, + Some(chain) => self.combine_chain(chain, defer), + }) + } + let variant_dtor = chain.unwrap_or_else(|| self.put_noop()); + + other = Some(match other { + None => variant_dtor, + Some(other) => { + self.put_self(); + self.put_discr(discr); + self.combine_either(other, variant_dtor) + } + }); + } + let variants_dtor = other.unwrap_or_else(|| self.put_noop()); + + let dtor = match surface { + None => variants_dtor, + Some(surface) => self.combine_chain(surface, variants_dtor), + }; + self.combine_fuse(dtor); + self.return_() + } + + fn build_chain(mut self, surface_drop: Option, elem_tys: I) -> Body<'tcx> + where + I: Iterator> + ExactSizeIterator, + { + let surface = match surface_drop { + None => None, + Some(kind) => { + self.put_self(); + Some(match kind { + SurfaceDropKind::Async => self.combine_async_surface(), + SurfaceDropKind::Sync => self.combine_sync_surface(), + }) + } + }; + + let mut chain = None; + for (field_idx, field_ty) in elem_tys.enumerate().map(|(i, ty)| (FieldIdx::new(i), ty)) { + self.put_field(field_idx, field_ty); + let defer = self.combine_defer(field_ty); + chain = Some(match chain { + None => defer, + Some(chain) => self.combine_chain(chain, defer), + }) + } + let chain = chain.unwrap_or_else(|| self.put_noop()); + + let dtor = match surface { + None => chain, + Some(surface) => self.combine_chain(surface, chain), + }; + self.combine_fuse(dtor); + self.return_() + } + + fn build_zst_output(mut self) -> Body<'tcx> { + self.put_zst_output(); + self.return_() + } + + fn build_fused_async_surface(mut self) -> Body<'tcx> { + self.put_self(); + let surface = self.combine_async_surface(); + self.combine_fuse(surface); + self.return_() + } + + fn build_fused_sync_surface(mut self) -> Body<'tcx> { + self.put_self(); + let surface = self.combine_sync_surface(); + self.combine_fuse(surface); + self.return_() + } + + fn build_slice(mut self, is_array: bool, elem_ty: Ty<'tcx>) -> Body<'tcx> { + if is_array { + self.put_array_as_slice(elem_ty) + } else { + self.put_self() + } + let dtor = self.combine_slice(elem_ty); + self.combine_fuse(dtor); + self.return_() + } + + fn put_zst_output(&mut self) { + let return_ty = self.locals[RETURN_PLACE].ty; + self.put_operand(Operand::Constant(Box::new(ConstOperand { + span: self.span, + user_ty: None, + const_: Const::zero_sized(return_ty), + }))); + } + + /// Puts `to_drop: *mut Self` on top of the stack. + fn put_self(&mut self) { + self.put_operand(Operand::Copy(Self::SELF_PTR.into())) + } + + /// Given that `Self is [ElemTy; N]` puts `to_drop: *mut [ElemTy]` + /// on top of the stack. + fn put_array_as_slice(&mut self, elem_ty: Ty<'tcx>) { + let slice_ptr_ty = Ty::new_mut_ptr(self.tcx, Ty::new_slice(self.tcx, elem_ty)); + self.put_temp_rvalue(Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize), + Operand::Copy(Self::SELF_PTR.into()), + slice_ptr_ty, + )) + } + + /// If given Self is a struct puts `to_drop: *mut FieldTy` on top + /// of the stack. + fn put_field(&mut self, field: FieldIdx, field_ty: Ty<'tcx>) { + let place = Place { + local: Self::SELF_PTR, + projection: self + .tcx + .mk_place_elems(&[PlaceElem::Deref, PlaceElem::Field(field, field_ty)]), + }; + self.put_temp_rvalue(Rvalue::AddressOf(Mutability::Mut, place)) + } + + /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of + /// the stack. + fn put_variant_field( + &mut self, + variant_sym: Symbol, + variant: VariantIdx, + field: FieldIdx, + field_ty: Ty<'tcx>, + ) { + let place = Place { + local: Self::SELF_PTR, + projection: self.tcx.mk_place_elems(&[ + PlaceElem::Deref, + PlaceElem::Downcast(Some(variant_sym), variant), + PlaceElem::Field(field, field_ty), + ]), + }; + self.put_temp_rvalue(Rvalue::AddressOf(Mutability::Mut, place)) + } + + /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of + /// the stack. + fn put_discr(&mut self, discr: Discr<'tcx>) { + let (size, _) = discr.ty.int_size_and_signed(self.tcx); + self.put_operand(Operand::const_from_scalar( + self.tcx, + discr.ty, + interpret::Scalar::from_uint(discr.val, size), + self.span, + )); + } + + /// Puts `x: RvalueType` on top of the stack. + fn put_temp_rvalue(&mut self, rvalue: Rvalue<'tcx>) { + let last_bb = &mut self.bbs[self.last_bb]; + debug_assert!(last_bb.terminator.is_none()); + let source_info = self.source_info; + + let local_ty = rvalue.ty(&self.locals, self.tcx); + // We need to create a new local to be able to "consume" it with + // a combinator + let local = self.locals.push(LocalDecl::with_source_info(local_ty, source_info)); + last_bb.statements.extend_from_slice(&[ + Statement { source_info, kind: StatementKind::StorageLive(local) }, + Statement { + source_info, + kind: StatementKind::Assign(Box::new((local.into(), rvalue))), + }, + ]); + + self.put_operand(Operand::Move(local.into())); + } + + /// Puts operand on top of the stack. + fn put_operand(&mut self, operand: Operand<'tcx>) { + if let Some(top_cleanup_bb) = &mut self.top_cleanup_bb { + let source_info = self.source_info; + match &operand { + Operand::Copy(_) | Operand::Constant(_) => { + *top_cleanup_bb = self.bbs.push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Goto { target: *top_cleanup_bb }, + }), + is_cleanup: true, + }); + } + Operand::Move(place) => { + let local = place.as_local().unwrap(); + *top_cleanup_bb = self.bbs.push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: if self.locals[local].ty.needs_drop(self.tcx, self.param_env) { + TerminatorKind::Drop { + place: local.into(), + target: *top_cleanup_bb, + unwind: UnwindAction::Terminate( + UnwindTerminateReason::InCleanup, + ), + replace: false, + } + } else { + TerminatorKind::Goto { target: *top_cleanup_bb } + }, + }), + is_cleanup: true, + }); + } + }; + } + self.stack.push(operand); + } + + /// Puts `noop: async_drop::Noop` on top of the stack + fn put_noop(&mut self) -> Ty<'tcx> { + self.apply_combinator(0, LangItem::AsyncDropNoop, &[]) + } + + fn combine_async_surface(&mut self) -> Ty<'tcx> { + self.apply_combinator(1, LangItem::SurfaceAsyncDropInPlace, &[self.self_ty.unwrap().into()]) + } + + fn combine_sync_surface(&mut self) -> Ty<'tcx> { + self.apply_combinator( + 1, + LangItem::AsyncDropSurfaceDropInPlace, + &[self.self_ty.unwrap().into()], + ) + } + + fn combine_fuse(&mut self, inner_future_ty: Ty<'tcx>) -> Ty<'tcx> { + self.apply_combinator(1, LangItem::AsyncDropFuse, &[inner_future_ty.into()]) + } + + fn combine_slice(&mut self, elem_ty: Ty<'tcx>) -> Ty<'tcx> { + self.apply_combinator(1, LangItem::AsyncDropSlice, &[elem_ty.into()]) + } + + fn combine_defer(&mut self, to_drop_ty: Ty<'tcx>) -> Ty<'tcx> { + self.apply_combinator(1, LangItem::AsyncDropDefer, &[to_drop_ty.into()]) + } + + fn combine_chain(&mut self, first: Ty<'tcx>, second: Ty<'tcx>) -> Ty<'tcx> { + self.apply_combinator(2, LangItem::AsyncDropChain, &[first.into(), second.into()]) + } + + fn combine_either(&mut self, other: Ty<'tcx>, matched: Ty<'tcx>) -> Ty<'tcx> { + self.apply_combinator( + 4, + LangItem::AsyncDropEither, + &[other.into(), matched.into(), self.self_ty.unwrap().into()], + ) + } + + fn return_(mut self) -> Body<'tcx> { + let last_bb = &mut self.bbs[self.last_bb]; + debug_assert!(last_bb.terminator.is_none()); + let source_info = self.source_info; + + let (1, Some(output)) = (self.stack.len(), self.stack.pop()) else { + span_bug!( + self.span, + "async destructor ctor shim builder finished with invalid number of stack items: expected 1 found {}", + self.stack.len(), + ) + }; + #[cfg(debug_assertions)] + if let Some(ty) = self.self_ty { + debug_assert_eq!( + output.ty(&self.locals, self.tcx), + ty.async_destructor_ty(self.tcx, self.param_env), + "output async destructor types did not match for type: {ty:?}", + ); + } + + let dead_storage = match &output { + Operand::Move(place) => Some(Statement { + source_info, + kind: StatementKind::StorageDead(place.as_local().unwrap()), + }), + _ => None, + }; + + last_bb.statements.extend( + iter::once(Statement { + source_info, + kind: StatementKind::Assign(Box::new((RETURN_PLACE.into(), Rvalue::Use(output)))), + }) + .chain(dead_storage), + ); + + last_bb.terminator = Some(Terminator { source_info, kind: TerminatorKind::Return }); + + let source = MirSource::from_instance(ty::InstanceDef::AsyncDropGlueCtorShim( + self.def_id, + self.self_ty, + )); + new_body(source, self.bbs, self.locals, Self::INPUT_COUNT, self.span) + } + + fn apply_combinator( + &mut self, + arity: usize, + function: LangItem, + args: &[ty::GenericArg<'tcx>], + ) -> Ty<'tcx> { + let function = self.tcx.require_lang_item(function, Some(self.span)); + let operands_split = self + .stack + .len() + .checked_sub(arity) + .expect("async destructor ctor shim combinator tried to consume too many items"); + let operands = &self.stack[operands_split..]; + + let func_ty = Ty::new_fn_def(self.tcx, function, args.iter().copied()); + let func_sig = func_ty.fn_sig(self.tcx).no_bound_vars().unwrap(); + #[cfg(debug_assertions)] + operands.iter().zip(func_sig.inputs()).for_each(|(operand, expected_ty)| { + let operand_ty = operand.ty(&self.locals, self.tcx); + if operand_ty == *expected_ty { + return; + } + + // If projection of Discriminant then compare with `Ty::discriminant_ty` + if let ty::Alias(ty::AliasKind::Projection, ty::AliasTy { args, def_id, .. }) = + expected_ty.kind() + && Some(*def_id) == self.tcx.lang_items().discriminant_type() + && args.first().unwrap().as_type().unwrap().discriminant_ty(self.tcx) == operand_ty + { + return; + } + + span_bug!( + self.span, + "Operand type and combinator argument type are not equal. + operand_ty: {:?} + argument_ty: {:?} +", + operand_ty, + expected_ty + ); + }); + + let target = self.bbs.push(BasicBlockData { + statements: operands + .iter() + .rev() + .filter_map(|o| { + if let Operand::Move(Place { local, projection }) = o { + assert!(projection.is_empty()); + Some(Statement { + source_info: self.source_info, + kind: StatementKind::StorageDead(*local), + }) + } else { + None + } + }) + .collect(), + terminator: None, + is_cleanup: false, + }); + + let dest_ty = func_sig.output(); + let dest = + self.locals.push(LocalDecl::with_source_info(dest_ty, self.source_info).immutable()); + + let unwind = if let Some(top_cleanup_bb) = &mut self.top_cleanup_bb { + for _ in 0..arity { + *top_cleanup_bb = + self.bbs[*top_cleanup_bb].terminator().successors().exactly_one().ok().unwrap(); + } + UnwindAction::Cleanup(*top_cleanup_bb) + } else { + UnwindAction::Unreachable + }; + + let last_bb = &mut self.bbs[self.last_bb]; + debug_assert!(last_bb.terminator.is_none()); + last_bb.statements.push(Statement { + source_info: self.source_info, + kind: StatementKind::StorageLive(dest), + }); + last_bb.terminator = Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { + span: self.span, + user_ty: None, + const_: Const::Val(ConstValue::ZeroSized, func_ty), + })), + destination: dest.into(), + target: Some(target), + unwind, + call_source: CallSource::Misc, + fn_span: self.span, + args: self.stack.drain(operands_split..).map(|o| respan(self.span, o)).collect(), + }, + }); + + self.put_operand(Operand::Move(dest.into())); + self.last_bb = target; + + dest_ty + } +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 36d623fd93e12..dd1065590b306 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -228,6 +228,7 @@ use rustc_middle::ty::{ TypeVisitableExt, VtblEntry, }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::EntryFnType; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Spanned}; @@ -966,13 +967,14 @@ fn visit_instance_use<'tcx>( ty::InstanceDef::ThreadLocalShim(..) => { bug!("{:?} being reified", instance); } - ty::InstanceDef::DropGlue(_, None) => { + ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => { // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { output.push(create_fn_mono_item(tcx, instance, source)); } } ty::InstanceDef::DropGlue(_, Some(_)) + | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 2a91d69529a85..cbab200618610 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -4,10 +4,9 @@ #[macro_use] extern crate tracing; -#[macro_use] -extern crate rustc_middle; use rustc_hir::lang_items::LangItem; +use rustc_middle::bug; use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 5a92657cb40d7..8f7b4c6472c90 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -103,6 +103,7 @@ use rustc_data_structures::sync; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_middle::mir::mono::{ @@ -625,7 +626,8 @@ fn characteristic_def_id_of_mono_item<'tcx>( | ty::InstanceDef::Virtual(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => return None, + | ty::InstanceDef::FnPtrAddrShim(..) + | ty::InstanceDef::AsyncDropGlueCtorShim(..) => return None, }; // If this is a method, we want to put it into the same module as @@ -769,7 +771,9 @@ fn mono_item_visibility<'tcx>( }; let def_id = match instance.def { - InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, + InstanceDef::Item(def_id) + | InstanceDef::DropGlue(def_id, Some(_)) + | InstanceDef::AsyncDropGlueCtorShim(def_id, Some(_)) => def_id, // We match the visibility of statics here InstanceDef::ThreadLocalShim(def_id) => { @@ -786,6 +790,7 @@ fn mono_item_visibility<'tcx>( | InstanceDef::ConstructCoroutineInClosureShim { .. } | InstanceDef::CoroutineKindShim { .. } | InstanceDef::DropGlue(..) + | InstanceDef::AsyncDropGlueCtorShim(..) | InstanceDef::CloneShim(..) | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, }; diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e2436759c22c5..873095dca8722 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -230,6 +230,10 @@ parse_expected_struct_field = expected one of `,`, `:`, or `{"}"}`, found `{$tok parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_expr_rarrow_call = `->` used for field access or method call + .suggestion = try using `.` instead + .help = the `.` operator will dereference the value if needed + parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements .label = dash-separated idents are not valid .suggestion = if the original crate name uses dashes you need to use underscores in the code @@ -620,6 +624,8 @@ parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allo parse_out_of_range_hex_escape = out of range hex escape .label = must be a character in the range [\x00-\x7f] +parse_outer_attr_ambiguous = ambiguous outer attributes + parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index eae2d904c35e1..d06f03a7c1767 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -495,6 +495,15 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { pub attributes: Span, } +#[derive(Diagnostic)] +#[diag(parse_outer_attr_ambiguous)] +pub(crate) struct AmbiguousOuterAttributes { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: WrapInParentheses, +} + #[derive(Diagnostic)] #[diag(parse_missing_in_in_for_loop)] pub(crate) struct MissingInInForLoop { @@ -1463,7 +1472,7 @@ impl Subdiagnostic for FnTraitMissingParen { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _: F, + _: &F, ) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); let applicability = if self.machine_applicable { @@ -2988,3 +2997,12 @@ pub(crate) struct AsyncImpl { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expr_rarrow_call)] +#[help] +pub(crate) struct ExprRArrowCall { + #[primary_span] + #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00947a4c5853f..8ed2a6edf1aec 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -327,7 +327,9 @@ impl<'a> Parser<'a> { this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); + self.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); + let span = lhs_span.to(rhs.span); + lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -426,6 +428,18 @@ impl<'a> Parser<'a> { }); } + fn error_ambiguous_outer_attrs(&self, lhs: &P, lhs_span: Span, rhs_span: Span) { + if let Some(attr) = lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer) { + self.dcx().emit_err(errors::AmbiguousOuterAttributes { + span: attr.span.to(rhs_span), + sugg: errors::WrapInParentheses::Expression { + left: attr.span.shrink_to_lo(), + right: lhs_span.shrink_to_hi(), + }, + }); + } + } + /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// @@ -506,7 +520,8 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); + self.error_ambiguous_outer_attrs(&lhs, lhs.span, rhs_span); + let span = lhs.span.to(rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); @@ -722,7 +737,8 @@ impl<'a> Parser<'a> { expr_kind: fn(P, P) -> ExprKind, ) -> PResult<'a, P> { let mk_expr = |this: &mut Self, lhs: P, rhs: P| { - this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) + this.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); + this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -979,6 +995,12 @@ impl<'a> Parser<'a> { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true } else { self.eat(&token::Dot) }; @@ -3807,16 +3829,6 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } - /// Create expression span ensuring the span of the parent node - /// is larger than the span of lhs and rhs, including the attributes. - fn mk_expr_sp(&self, lhs: &P, lhs_span: Span, rhs_span: Span) -> Span { - lhs.attrs - .iter() - .find(|a| a.style == AttrStyle::Outer) - .map_or(lhs_span, |a| a.span) - .to(rhs_span) - } - fn collect_tokens_for_expr( &mut self, attrs: AttrWrapper, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 84ecd0a0de54f..848277c4611e3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -686,6 +686,8 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; + let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; + let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { Some(self.parse_block()?) } else { @@ -695,11 +697,9 @@ impl<'a> Parser<'a> { let span = span.to(self.prev_token.span); self.psess.gated_spans.gate(sym::fn_delegation, span); - let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty()); - Ok(( - ident, - ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })), - )) + let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); + let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body }; + Ok((ident, ItemKind::Delegation(Box::new(deleg)))) } fn parse_item_list( @@ -1191,7 +1191,11 @@ impl<'a> Parser<'a> { ident_span: ident.span, const_span, }); - ForeignItemKind::Static(ty, Mutability::Not, expr) + ForeignItemKind::Static(Box::new(StaticForeignItem { + ty, + mutability: Mutability::Not, + expr, + })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4a996f89a9a3d..7486da33b2173 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -162,7 +162,6 @@ pub struct Parser<'a> { /// /// See the comments in the `parse_path_segment` function for more details. unmatched_angle_bracket_count: u16, - max_angle_bracket_count: u16, angle_bracket_nesting: u16, last_unexpected_token_span: Option, @@ -430,7 +429,6 @@ impl<'a> Parser<'a> { num_bump_calls: 0, break_last_token: false, unmatched_angle_bracket_count: 0, - max_angle_bracket_count: 0, angle_bracket_nesting: 0, last_unexpected_token_span: None, subparser_name, @@ -778,7 +776,6 @@ impl<'a> Parser<'a> { if ate { // See doc comment for `unmatched_angle_bracket_count`. self.unmatched_angle_bracket_count += 1; - self.max_angle_bracket_count += 1; debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); } ate @@ -898,6 +895,7 @@ impl<'a> Parser<'a> { } // Attempt to keep parsing if it was an omitted separator. + self.last_unexpected_token_span = None; match f(self) { Ok(t) => { // Parsed successfully, therefore most probably the code only @@ -1254,8 +1252,6 @@ impl<'a> Parser<'a> { fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P> { if pat { self.psess.gated_spans.gate(sym::inline_const_pat, span); - } else { - self.psess.gated_spans.gate(sym::inline_const, span); } self.eat_keyword(kw::Const); let (attrs, blk) = self.parse_inner_attrs_and_block()?; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 0f410772dd980..b97ec8c613d91 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -299,7 +299,6 @@ impl<'a> Parser<'a> { // parsing a new path. if style == PathStyle::Expr { self.unmatched_angle_bracket_count = 0; - self.max_angle_bracket_count = 0; } // Generic arguments are found - `<`, `(`, `::<` or `::(`. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 7fc523ffe0dea..a545c170297de 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -353,7 +353,7 @@ passes_incorrect_meta_item = expected a quoted string literal passes_incorrect_meta_item_suggestion = consider surrounding this with quotes passes_incorrect_target = - `{$name}` language item must be applied to a {$kind} with {$at_least -> + `{$name}` lang item must be applied to a {$kind} with {$at_least -> [true] at least {$num} *[false] {$num} } generic {$num -> @@ -394,12 +394,21 @@ passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export] passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments +passes_lang_item_fn = {$name -> + [panic_impl] `#[panic_handler]` + *[other] `{$name}` lang item +} function + passes_lang_item_fn_with_target_feature = - `{$name}` language item function is not allowed to have `#[target_feature]` - .label = `{$name}` language item function is not allowed to have `#[target_feature]` + {passes_lang_item_fn} is not allowed to have `#[target_feature]` + .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]` + +passes_lang_item_fn_with_track_caller = + {passes_lang_item_fn} is not allowed to have `#[track_caller]` + .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]` passes_lang_item_on_incorrect_target = - `{$name}` language item must be applied to a {$expected_target} + `{$name}` lang item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} passes_layout_abi = @@ -455,7 +464,7 @@ passes_missing_const_stab_attr = {$descr} has missing const stability attribute passes_missing_lang_item = - language item required, but not found: `{$name}` + lang item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` @@ -696,8 +705,8 @@ passes_unknown_feature = unknown feature `{$feature}` passes_unknown_lang_item = - definition of an unknown language item: `{$name}` - .label = definition of unknown language item `{$name}` + definition of an unknown lang item: `{$name}` + .label = definition of unknown lang item `{$name}` passes_unlabeled_cf_in_while_condition = `break` or `continue` with no label in the condition of a `while` loop diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 986ef69ad8849..0c3dd649997ef 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -1,6 +1,7 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1254ae8cfc8db..c403e9196fab2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,14 +11,15 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_hir as hir; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_macros::LintDiagnostic; +use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; @@ -519,7 +520,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); false } - Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, + Target::Fn => { + // `#[track_caller]` is not valid on weak lang items because they are called via + // `extern` declarations and `#[track_caller]` would alter their ABI. + if let Some((lang_item, _)) = hir::lang_items::extract(attrs) + && let Some(item) = hir::LangItem::from_name(lang_item) + && item.is_weak() + { + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); + + self.dcx().emit_err(errors::LangItemWithTrackCaller { + attr_span, + name: lang_item, + sig_span: sig.span, + }); + false + } else { + true + } + } + Target::Method(..) | Target::ForeignFn | Target::Closure => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[track_caller]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible @@ -602,7 +622,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { match target { Target::Fn => { - // `#[target_feature]` is not allowed in language items. + // `#[target_feature]` is not allowed in lang items. if let Some((lang_item, _)) = hir::lang_items::extract(attrs) // Calling functions with `#[target_feature]` is // not unsafe on WASM, see #84988 diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 4a1a204908355..eb29a65cb293d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -13,6 +13,7 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 51f288b3c9595..933412f677ce8 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -16,6 +16,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3f26ea4507d41..03a607348e88c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -819,6 +819,16 @@ pub struct MissingLangItem { pub name: Symbol, } +#[derive(Diagnostic)] +#[diag(passes_lang_item_fn_with_track_caller)] +pub struct LangItemWithTrackCaller { + #[primary_span] + pub attr_span: Span, + pub name: Symbol, + #[label] + pub sig_span: Span, +} + #[derive(Diagnostic)] #[diag(passes_lang_item_fn_with_target_feature)] pub struct LangItemWithTargetFeature { @@ -1755,7 +1765,7 @@ impl Subdiagnostic for UnusedVariableStringInterp { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 49408c5618b0e..d7664d1c1fff7 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -498,7 +498,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { (self, i, i.kind, Id::None, ast, ForeignItem, ForeignItemKind), [Static, Fn, TyAlias, MacCall] ); - ast_visit::walk_foreign_item(self, i) + ast_visit::walk_item(self, i) } fn visit_item(&mut self, i: &'v ast::Item) { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index d1368267224a7..c1da8928f3021 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -1,4 +1,4 @@ -//! Detecting language items. +//! Detecting lang items. //! //! Language items are items that represent concepts intrinsic to the language //! itself. Examples are: diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 8d223c23363bb..82d43f078ee27 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,6 +1,7 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index e03052bcfede8..d3608759eec70 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -8,13 +8,10 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![feature(generic_nonzero)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(try_blocks)] -#[macro_use] -extern crate rustc_middle; #[macro_use] extern crate tracing; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c7729302783fc..b50cb158b1fed 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,6 +94,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index e10a22cdf31b9..4b5c4dfe991b7 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -6,6 +6,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 869cbebbc0def..d5e1a70fd45c4 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 4eb0c6c275e61..90691ca17908b 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -14,7 +14,7 @@ use crate::errors::{ }; /// Checks the crate for usage of weak lang items, returning a vector of all the -/// language items required by this crate, but not defined yet. +/// lang items required by this crate, but not defined yet. pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems, krate: &ast::Crate) { // These are never called by user code, they're generated by the compiler. // They will never implicitly be added to the `missing` array unless we do diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 75b7b7c8f6784..27f227e6d9c11 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -65,7 +65,7 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _: F, + _: &F, ) { let Overlap { span, range } = self; @@ -113,7 +113,7 @@ impl<'tcx> Subdiagnostic for GappedRange<'tcx> { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _: F, + _: &F, ) { let GappedRange { span, gap, first_range } = self; diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 6e8843d904977..4155540886a65 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -14,12 +14,6 @@ pub mod pat_column; pub mod rustc; pub mod usefulness; -#[macro_use] -extern crate tracing; -#[cfg(feature = "rustc")] -#[macro_use] -extern crate rustc_middle; - #[cfg(feature = "rustc")] rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 3ca5ebdb0dd13..1d10c9df4ab29 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -1,11 +1,11 @@ -use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_span::ErrorGuaranteed; - use crate::constructor::Constructor; use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered}; use crate::pat_column::PatternColumn; use crate::rustc::{RevealedTy, RustcPatCtxt, WitnessPat}; use crate::MatchArm; +use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_span::ErrorGuaranteed; +use tracing::instrument; /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned /// in a given column. diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 548a7b4300552..ff68dd81beaf2 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -11,6 +11,7 @@ use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, FieldPat, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, FieldDef, OpaqueTypeKey, Ty, TyCtxt, TypeVisitableExt, VariantDef}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 7246039174aff..74af9154f8581 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -709,16 +709,15 @@ //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific //! reason not to, for example if they crucially depend on a particular feature like `or_patterns`. +use self::PlaceValidity::*; +use crate::constructor::{Constructor, ConstructorSet, IntRange}; +use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; +use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; use rustc_hash::FxHashSet; use rustc_index::bit_set::BitSet; use smallvec::{smallvec, SmallVec}; use std::fmt; - -use crate::constructor::{Constructor, ConstructorSet, IntRange}; -use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; -use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; - -use self::PlaceValidity::*; +use tracing::{debug, instrument}; #[cfg(feature = "rustc")] use rustc_data_structures::stack::ensure_sufficient_stack; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 2039e994aaae0..a78f7e65981ab 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -6,9 +6,6 @@ #![feature(try_blocks)] #![feature(let_chains)] -#[macro_use] -extern crate tracing; - mod errors; use rustc_ast::visit::{try_visit, VisitorResult}; @@ -31,6 +28,7 @@ use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; +use tracing::debug; use std::fmt; use std::marker::PhantomData; diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 3373835d813e7..914481d712e8e 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,7 +3,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature(generic_nonzero)] #![feature(min_specialization)] #![feature(rustc_attrs)] #![allow(rustc::potential_query_instability, unused_parens)] diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 17f96896a504b..5f1a03502a70f 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -49,6 +49,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; use rustc_data_structures::AtomicRef; use rustc_hir::definitions::DefPathHash; +use rustc_macros::{Decodable, Encodable}; use std::fmt; use std::hash::Hash; @@ -75,8 +76,6 @@ impl DepKind { } } -static_assert_size!(DepKind, 2); - pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DepKind").field("variant", &kind.variant).finish() } @@ -96,15 +95,6 @@ pub struct DepNode { pub hash: PackedFingerprint, } -// We keep a lot of `DepNode`s in memory during compilation. It's not -// required that their size stay the same, but we don't want to change -// it inadvertently. This assert just ensures we're aware of any change. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 18); - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -static_assert_size!(DepNode, 24); - impl DepNode { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually @@ -285,8 +275,7 @@ pub struct DepKindStruct { /// some independent path or string that persists between runs without /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(Encodable, Decodable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub struct WorkProductId { hash: Fingerprint, } @@ -316,3 +305,17 @@ unsafe impl StableOrd for WorkProductId { // Fingerprint can use unstable (just a tuple of `u64`s), so WorkProductId can as well const CAN_USE_UNSTABLE_SORT: bool = true; } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // tidy-alphabetical-start + static_assert_size!(DepKind, 2); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + static_assert_size!(DepNode, 18); + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + static_assert_size!(DepNode, 24); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 534937003ebfd..76227a78c3d68 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -6,6 +6,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; +use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; @@ -14,6 +15,7 @@ use std::hash::Hash; use std::marker::PhantomData; use std::sync::atomic::Ordering; use std::sync::Arc; +use tracing::{debug, instrument}; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; @@ -40,6 +42,11 @@ rustc_index::newtype_index! { pub struct DepNodeIndex {} } +// We store a large collection of these in `prev_index_to_index` during +// non-full incremental builds, and want to ensure that the element size +// doesn't inadvertently increase. +rustc_data_structures::static_assert_size!(Option, 4); + impl DepNodeIndex { const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO; pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1); @@ -459,7 +466,8 @@ impl DepGraph { } TaskDepsRef::Ignore => return, TaskDepsRef::Forbid => { - panic!("Illegal read of: {dep_node_index:?}") + // Reading is forbidden in this context. ICE with a useful error message. + panic_on_forbidden_read(data, dep_node_index) } }; let task_deps = &mut *task_deps; @@ -1105,11 +1113,6 @@ impl CurrentDepGraph { Err(_) => None, }; - // We store a large collection of these in `prev_index_to_index` during - // non-full incremental builds, and want to ensure that the element size - // doesn't inadvertently increase. - static_assert_size!(Option, 4); - let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200; CurrentDepGraph { @@ -1366,3 +1369,45 @@ pub(crate) fn print_markframe_trace(graph: &DepGraph, frame: Option< eprintln!("end of try_mark_green dep node stack"); } + +#[cold] +#[inline(never)] +fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepNodeIndex) -> ! { + // We have to do an expensive reverse-lookup of the DepNode that + // corresponds to `dep_node_index`, but that's OK since we are about + // to ICE anyway. + let mut dep_node = None; + + // First try to find the dep node among those that already existed in the + // previous session + for (prev_index, index) in data.current.prev_index_to_index.lock().iter_enumerated() { + if index == &Some(dep_node_index) { + dep_node = Some(data.previous.index_to_node(prev_index)); + break; + } + } + + if dep_node.is_none() { + // Try to find it among the new nodes + for shard in data.current.new_node_to_index.lock_shards() { + if let Some((node, _)) = shard.iter().find(|(_, index)| **index == dep_node_index) { + dep_node = Some(*node); + break; + } + } + } + + let dep_node = dep_node.map_or_else( + || format!("with index {:?}", dep_node_index), + |dep_node| format!("`{:?}`", dep_node), + ); + + panic!( + "Error: trying to record dependency on DepNode {dep_node} in a \ + context that does not allow it (e.g. during query deserialization). \ + The most common case of recording a dependency on a DepNode `foo` is \ + when the correspondng query `foo` is invoked. Invoking queries is not \ + allowed as part of loading something from the incremental on-disk cache. \ + See ." + ) +} diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index feb69ecd07867..cbd8029588701 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -11,13 +11,12 @@ pub use graph::{hash_result, DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, W pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use self::graph::{print_markframe_trace, MarkFrame}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_session::Session; - use std::panic; - -use self::graph::{print_markframe_trace, MarkFrame}; +use tracing::instrument; pub trait DepContext: Copy { type Deps: Deps; diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 6042aa6a2d29b..b426bb888f460 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -51,6 +51,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::iter; use std::marker::PhantomData; use std::sync::Arc; +use tracing::{debug, instrument}; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits // unused so that we can store multiple index types in `CompressedHybridIndex`, diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 6a959a99e5d42..fa07877ab9f3e 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,18 +1,10 @@ #![feature(assert_matches)] #![feature(core_intrinsics)] -#![feature(generic_nonzero)] #![feature(hash_raw_entry)] #![feature(min_specialization)] #![feature(let_chains)] #![allow(rustc::potential_query_instability, internal_features)] -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_data_structures; -#[macro_use] -extern crate rustc_macros; - pub mod cache; pub mod dep_graph; mod error; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 91a0026f281eb..ab4f48fcd3206 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -20,6 +20,7 @@ use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::sync::Lock; use rustc_errors::DiagInner; use rustc_hir::def::DefKind; +use rustc_macros::{Decodable, Encodable}; use rustc_span::def_id::DefId; use rustc_span::Span; use thin_vec::ThinVec; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3d9848395a20b..d37d5bce9cc36 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -27,6 +27,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::mem; use thin_vec::ThinVec; +use tracing::instrument; use super::QueryConfig; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 1b6387acf71e2..8068ea1a40773 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1304,11 +1304,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { visit::walk_item(self, item); macro_rules_scope } - ItemKind::MacCall(..) => { - let macro_rules_scope = self.visit_invoc_in_module(item.id); - visit::walk_item(self, item); - macro_rules_scope - } + ItemKind::MacCall(..) => self.visit_invoc_in_module(item.id), _ => { let orig_macro_rules_scope = self.parent_scope.macro_rules; self.build_reduced_graph_for_item(item); @@ -1339,7 +1335,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } self.build_reduced_graph_for_foreign_item(foreign_item); - visit::walk_foreign_item(self, foreign_item); + visit::walk_item(self, foreign_item); } fn visit_block(&mut self, block: &'b Block) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index bef95aca0d1cc..a27a6bceda335 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -136,14 +136,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) } - ItemKind::MacCall(..) => { - visit::walk_item(self, i); - return self.visit_macro_invoc(i.id); - } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, - ItemKind::Use(..) => { - return visit::walk_item(self, i); - } + ItemKind::Use(..) => return visit::walk_item(self, i), + ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), }; let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); @@ -214,7 +209,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(_, mutability, _) => { + ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability, expr: _ }) => { DefKind::Static { mutability, nested: false } } ForeignItemKind::Fn(_) => DefKind::Fn, @@ -224,7 +219,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span); - self.with_parent(def, |this| visit::walk_foreign_item(this, fi)); + self.with_parent(def, |this| visit::walk_item(this, fi)); } fn visit_variant(&mut self, v: &'a Variant) { diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index b0329702d1143..edfeacec7e3b7 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{codes::*, Applicability, MultiSpan}; +use rustc_errors::{codes::*, Applicability, ElidedLifetimeInPathSubdiag, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -907,6 +907,8 @@ pub(crate) struct ExplicitAnonymousLivetimeReportError { pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[primary_span] pub(crate) span: Span, + #[subdiagnostic] + pub(crate) subdiag: ElidedLifetimeInPathSubdiag, } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 753ba09d88686..6c870ddfd227a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,6 +21,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; +use rustc_middle::ty::DelegationFnSig; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -885,7 +886,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, kind: LifetimeBinderKind::Item, span: generics.span, }, - |this| visit::walk_foreign_item(this, foreign_item), + |this| visit::walk_item(this, foreign_item), ); } ForeignItemKind::Fn(box Fn { ref generics, .. }) => { @@ -897,13 +898,11 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, kind: LifetimeBinderKind::Function, span: generics.span, }, - |this| visit::walk_foreign_item(this, foreign_item), + |this| visit::walk_item(this, foreign_item), ); } ForeignItemKind::Static(..) => { - self.with_static_rib(def_kind, |this| { - visit::walk_foreign_item(this, foreign_item); - }); + self.with_static_rib(def_kind, |this| visit::walk_item(this, foreign_item)) } ForeignItemKind::MacCall(..) => { panic!("unexpanded macro in resolve!") @@ -1883,20 +1882,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // async fn foo(_: std::cell::Ref) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { - let mut err = - self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere { - span: path_span, - }); let sess = self.r.tcx.sess; - rustc_errors::add_elided_lifetime_in_path_suggestion( + let subdiag = rustc_errors::elided_lifetime_in_path_suggestion( sess.source_map(), - &mut err, expected_lifetimes, path_span, !segment.has_generic_args, elided_lifetime_span, ); - err.emit(); + self.r.dcx().emit_err(errors::ImplicitElidedLifetimeNotAllowedHere { + span: path_span, + subdiag, + }); should_lint = false; for id in node_ids { @@ -4751,12 +4748,13 @@ struct ItemInfoCollector<'a, 'b, 'tcx> { impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) { - let def_id = self.r.local_def_id(id); - self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len()); - - if sig.decl.has_self() { - self.r.has_self.insert(def_id); - } + let sig = DelegationFnSig { + header: sig.header, + param_count: sig.decl.inputs.len(), + has_self: sig.decl.has_self(), + c_variadic: sig.decl.c_variadic(), + }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d79c638fa0789..64451030adf0f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2039,7 +2039,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType, ast::AssocItemKind::Delegation(..) - if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) => + if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)] + .has_self => { AssocSuggestion::MethodWithSelf { called } } @@ -2062,7 +2063,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if filter_fn(res) { let def_id = res.def_id(); let has_self = match def_id.as_local() { - Some(def_id) => self.r.has_self.contains(&def_id), + Some(def_id) => { + self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self) + } None => self .r .tcx diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b8221d9d7f9f0..af0b4792136cf 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -38,12 +38,12 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; use rustc_errors::{Applicability, Diag, ErrCode}; -use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; +use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::NonMacroAttrKind; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::IndexVec; @@ -52,8 +52,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt, TyCtxtFeed}; -use rustc_middle::ty::{Feed, ResolverGlobalCtxt, ResolverOutputs}; +use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTools}; +use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::LintBuffer; @@ -959,7 +959,7 @@ enum BuiltinMacroState { } struct DeriveData { - resolutions: DeriveResolutions, + resolutions: Vec, helper_attrs: Vec<(usize, Ident)>, has_derive_copy: bool, } @@ -992,7 +992,6 @@ pub struct Resolver<'a, 'tcx> { extern_prelude: FxHashMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. - has_self: LocalDefIdSet, field_def_ids: LocalDefIdMap<&'tcx [DefId]>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. @@ -1042,7 +1041,7 @@ pub struct Resolver<'a, 'tcx> { block_map: NodeMap>, /// A fake module that contains no definition and no prelude. Used so that /// some AST passes can generate identifiers that only resolve to local or - /// language items. + /// lang items. empty_module: Module<'a>, module_map: FxHashMap>, binding_parent_modules: FxHashMap, Module<'a>>, @@ -1149,8 +1148,7 @@ pub struct Resolver<'a, 'tcx> { legacy_const_generic_args: FxHashMap>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, - /// Amount of parameters for each function in the crate. - fn_parameter_counts: LocalDefIdMap, + delegation_fn_sigs: LocalDefIdMap, main_def: Option, trait_impls: FxIndexMap>, @@ -1399,7 +1397,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prelude: None, extern_prelude, - has_self: Default::default(), field_def_ids: Default::default(), field_visibility_spans: FxHashMap::default(), @@ -1508,7 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), - fn_parameter_counts: Default::default(), + delegation_fn_sigs: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1621,8 +1618,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), - has_self: self.has_self, - fn_parameter_counts: self.fn_parameter_counts, + delegation_fn_sigs: self.delegation_fn_sigs, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 2a23ed71753fa..82e41b6c31436 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -15,7 +15,7 @@ use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, StashKey}; -use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; +use rustc_expand::base::{Annotatable, DeriveResolution, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion}; @@ -344,7 +344,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { &mut self, expn_id: LocalExpnId, force: bool, - derive_paths: &dyn Fn() -> DeriveResolutions, + derive_paths: &dyn Fn() -> Vec, ) -> Result<(), Indeterminate> { // Block expansion of the container until we resolve all derives in it. // This is required for two reasons: @@ -360,11 +360,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { has_derive_copy: false, }); let parent_scope = self.invocation_parent_scopes[&expn_id]; - for (i, (path, _, opt_ext, _)) in entry.resolutions.iter_mut().enumerate() { - if opt_ext.is_none() { - *opt_ext = Some( + for (i, resolution) in entry.resolutions.iter_mut().enumerate() { + if resolution.exts.is_none() { + resolution.exts = Some( match self.resolve_macro_path( - path, + &resolution.path, Some(MacroKind::Derive), &parent_scope, true, @@ -372,7 +372,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { - let last_seg = path.segments.last().unwrap(); + let last_seg = resolution.path.segments.last().unwrap(); let span = last_seg.ident.span.normalize_to_macros_2_0(); entry.helper_attrs.extend( ext.helper_attrs @@ -416,7 +416,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { Ok(()) } - fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option { + fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option> { self.derive_data.remove(&expn_id).map(|data| data.resolutions) } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 0bc7579918ccf..aace0f3fef9f1 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -6,8 +6,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; +use std::mem; use std::ops::Range; -use std::{cmp, mem}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DocFragmentKind { @@ -129,17 +129,20 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { let Some(min_indent) = docs .iter() .map(|fragment| { - fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| { - if line.chars().all(|c| c.is_whitespace()) { - min_indent - } else { + fragment + .doc + .as_str() + .lines() + .filter(|line| line.chars().any(|c| !c.is_whitespace())) + .map(|line| { // Compare against either space or tab, ignoring whether they are // mixed or not. let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count(); - cmp::min(min_indent, whitespace) - + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add } - } - }) + whitespace + + (if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }) + }) + .min() + .unwrap_or(usize::MAX) }) .min() else { @@ -151,13 +154,13 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { continue; } - let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { + let indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { min_indent - add } else { min_indent }; - fragment.indent = min_indent; + fragment.indent = indent; } } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 5a9403e0a8590..532b749f9136b 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -8,11 +8,8 @@ #![doc(rust_logo)] #![allow(internal_features)] #![feature(rustdoc_internals)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(const_option)] #![feature(core_intrinsics)] -#![feature(generic_nonzero)] -#![feature(inline_const)] #![feature(min_specialization)] #![feature(never_type)] #![feature(ptr_sub_ptr)] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d5b22f841d273..ad66e5e1c2b4d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -15,6 +15,7 @@ use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg}; use rustc_feature::UnstableFeatures; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; @@ -32,6 +33,7 @@ use std::iter; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::LazyLock; +use tracing::debug; mod cfg; pub mod sigpipe; @@ -146,10 +148,26 @@ pub enum InstrumentCoverage { /// Individual flag values controlled by `-Z coverage-options`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] pub struct CoverageOptions { - /// Add branch coverage instrumentation. - pub branch: bool, - /// Add mcdc coverage instrumentation. - pub mcdc: bool, + pub level: CoverageLevel, + // Other boolean or enum-valued options might be added here. +} + +/// Controls whether branch coverage or MC/DC coverage is enabled. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum CoverageLevel { + /// Instrument for coverage at the MIR block level. + Block, + /// Also instrument branch points (includes block coverage). + Branch, + /// Instrument for MC/DC. Mostly a superset of branch coverage, but might + /// differ in some corner cases. + Mcdc, +} + +impl Default for CoverageLevel { + fn default() -> Self { + Self::Block + } } /// Settings for `-Z instrument-xray` flag. @@ -1888,9 +1906,12 @@ fn collect_print_requests( let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); let prints = prints.join(", "); - early_dcx.early_fatal(format!( - "unknown print request `{req}`. Valid print requests are: {prints}" - )); + + let mut diag = + early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); + #[allow(rustc::diagnostic_outside_of_impl)] + diag.help(format!("valid print requests are: {prints}")); + diag.emit() } }; @@ -2548,7 +2569,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let mut search_paths = vec![]; for s in &matches.opt_strs("L") { - search_paths.push(SearchPath::from_cli_opt(&sysroot, &target_triple, early_dcx, s)); + search_paths.push(SearchPath::from_cli_opt( + &sysroot, + &target_triple, + early_dcx, + s, + unstable_opts.unstable_options, + )); } let working_dir = std::env::current_dir().unwrap_or_else(|e| { diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index cb6656bae062c..2c20c3f0e1a34 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,8 +6,11 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use rustc_ast as ast; use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{ + CrateNum, DefId, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE, +}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -217,7 +220,6 @@ pub trait CrateStore: std::fmt::Debug { // incr. comp. uses to identify a CrateNum. fn crate_name(&self, cnum: CrateNum) -> Symbol; fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId; - fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum; } pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; @@ -227,4 +229,6 @@ pub struct Untracked { /// Reference span for definitions. pub source_span: AppendOnlyIndexVec, pub definitions: FreezeLock, + /// The interned [StableCrateId]s. + pub stable_crate_ids: FreezeLock, } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 2e4c7d14ecdf4..dce56382a53a0 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ codes::*, Diag, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, MultiSpan, }; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index aecf5954c4ca9..f4e2436efb9fb 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,13 +1,12 @@ //! A module for searching for libraries -use rustc_fs_util::try_canonicalize; +use crate::search_paths::{PathKind, SearchPath}; +use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use smallvec::{smallvec, SmallVec}; use std::env; use std::fs; use std::path::{Path, PathBuf}; - -use crate::search_paths::{PathKind, SearchPath}; -use rustc_fs_util::fix_windows_verbatim_for_gcc; +use tracing::debug; #[derive(Clone)] pub struct FileSearch<'a> { diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index c63af90a7f312..ce866906e1e69 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(generic_nonzero)] #![feature(let_chains)] #![feature(lazy_cell)] #![feature(option_get_or_insert_default)] @@ -7,13 +6,8 @@ #![feature(iter_intersperse)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_macros; pub mod errors; -#[macro_use] -extern crate tracing; - pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; pub use rustc_lint_defs as lint; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d51080589481b..7355e5b695347 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1,5 +1,4 @@ use crate::config::*; - use crate::search_paths::SearchPath; use crate::utils::NativeLib; use crate::{lint, EarlyDiagCtxt}; @@ -8,20 +7,17 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::ColorConfig; use rustc_errors::{LanguageIdentifier, TerminalUrl}; +use rustc_feature::UnstableFeatures; +use rustc_span::edition::Edition; +use rustc_span::RealFileName; +use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{ CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet, WasmCAbi, }; use rustc_target::spec::{ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, }; - -use rustc_feature::UnstableFeatures; -use rustc_span::edition::Edition; -use rustc_span::RealFileName; -use rustc_span::SourceFileHashAlgorithm; - use std::collections::BTreeMap; - use std::hash::{DefaultHasher, Hasher}; use std::num::{IntErrorKind, NonZero}; use std::path::PathBuf; @@ -118,8 +114,8 @@ top_level_options!( /// incremental compilation cache before proceeding. /// /// - `[TRACKED_NO_CRATE_HASH]` - /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that only - /// affect the incremental cache. + /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that + /// only affect the incremental cache. /// /// - `[UNTRACKED]` /// Incremental compilation is not influenced by this option. @@ -398,7 +394,7 @@ mod desc { pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = parse_bool; - pub const parse_coverage_options: &str = "either `no-branch`, `branch` or `mcdc`"; + pub const parse_coverage_options: &str = "`block` | `branch` | `mcdc`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -950,15 +946,9 @@ mod parse { for option in v.split(',') { match option { - "no-branch" => { - slot.branch = false; - slot.mcdc = false; - } - "branch" => slot.branch = true, - "mcdc" => { - slot.branch = true; - slot.mcdc = true; - } + "block" => slot.level = CoverageLevel::Block, + "branch" => slot.level = CoverageLevel::Branch, + "mcdc" => slot.level = CoverageLevel::Mcdc, _ => return false, } } @@ -1362,10 +1352,20 @@ mod parse { slot: &mut CollapseMacroDebuginfo, v: Option<&str>, ) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + CollapseMacroDebuginfo::Yes + } else { + CollapseMacroDebuginfo::No + }; + return true; + } + } + *slot = match v { - Some("no") => CollapseMacroDebuginfo::No, Some("external") => CollapseMacroDebuginfo::External, - Some("yes") => CollapseMacroDebuginfo::Yes, _ => return false, }; true @@ -1464,6 +1464,9 @@ options! { "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option = (None, parse_opt_number, [UNTRACKED], "divide crate into N units to optimize in parallel"), + collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified, + parse_collapse_macro_debuginfo, [TRACKED], + "set option to collapse debuginfo for macros"), control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], "use Windows Control Flow Guard (default: no)"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], @@ -1611,9 +1614,6 @@ options! { "show all expected values in check-cfg diagnostics (default: no)"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), - collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified, - parse_collapse_macro_debuginfo, [TRACKED], - "set option to collapse debuginfo for macros"), combine_cgu: bool = (false, parse_bool, [TRACKED], "combine CGUs into a single one"), coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED], @@ -1624,8 +1624,6 @@ options! { "threshold to allow cross crate inlining of functions"), debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], "emit discriminators and other data necessary for AutoFDO"), - debug_macros: bool = (false, parse_bool, [TRACKED], - "emit line numbers debug info inside macros (default: no)"), debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED], "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 16dd40acef047..5e8adffc249e6 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -1,5 +1,6 @@ use crate::filesearch::make_target_lib_path; use crate::EarlyDiagCtxt; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_target::spec::TargetTriple; use std::path::{Path, PathBuf}; @@ -52,6 +53,7 @@ impl SearchPath { triple: &TargetTriple, early_dcx: &EarlyDiagCtxt, path: &str, + is_unstable_enabled: bool, ) -> Self { let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") { (PathKind::Native, stripped) @@ -68,6 +70,14 @@ impl SearchPath { }; let dir = match path.strip_prefix("@RUSTC_BUILTIN") { Some(stripped) => { + if !is_unstable_enabled { + #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable + early_dcx.early_fatal( + "the `-Z unstable-options` flag must also be passed to \ + enable the use of `@RUSTC_BUILTIN`", + ); + } + make_target_lib_path(sysroot, triple.triple()).join("builtin").join(stripped) } None => PathBuf::from(path), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 2bc14b43234d0..db01bb90d6fac 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,8 +1,8 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType, - RemapPathScopeComponents, SwitchWithOptPath, + self, CoverageLevel, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, + OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::config::{ErrorOutputType, Input}; use crate::errors; @@ -349,11 +349,13 @@ impl Session { } pub fn instrument_coverage_branch(&self) -> bool { - self.instrument_coverage() && self.opts.unstable_opts.coverage_options.branch + self.instrument_coverage() + && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Branch } pub fn instrument_coverage_mcdc(&self) -> bool { - self.instrument_coverage() && self.opts.unstable_opts.coverage_options.mcdc + self.instrument_coverage() + && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc } pub fn is_sanitizer_cfi_enabled(&self) -> bool { diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 58de5cb31a513..f70a53eeb4108 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -1,6 +1,7 @@ use crate::session::Session; use rustc_data_structures::profiling::VerboseTimingGuard; use rustc_fs_util::try_canonicalize; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use std::{ path::{Path, PathBuf}, sync::OnceLock, diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs index c0c088bcef7dc..39e4541349ecd 100644 --- a/compiler/rustc_session/src/version.rs +++ b/compiler/rustc_session/src/version.rs @@ -1,3 +1,4 @@ +use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic}; use std::fmt::{self, Display}; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 61bbedf9eec9d..fd31c020f899a 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -500,6 +500,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { matches!(instance.def, ty::InstanceDef::DropGlue(_, None)) } + fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + let tables = self.0.borrow_mut(); + let instance = tables.instances[def]; + matches!(instance.def, ty::InstanceDef::AsyncDropGlueCtorShim(_, None)) + } + fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 7c0216211034c..452ab04c44c54 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -229,7 +229,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind { use rustc_middle::mir::BorrowKind::*; match *self { Shared => stable_mir::mir::BorrowKind::Shared, - Fake => stable_mir::mir::BorrowKind::Fake, + Fake(kind) => stable_mir::mir::BorrowKind::Fake(kind.stable(tables)), Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) }, } } @@ -247,6 +247,17 @@ impl<'tcx> Stable<'tcx> for mir::MutBorrowKind { } } +impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { + type T = stable_mir::mir::FakeBorrowKind; + fn stable(&self, _: &mut Tables<'_>) -> Self::T { + use rustc_middle::mir::FakeBorrowKind::*; + match *self { + Deep => stable_mir::mir::FakeBorrowKind::Deep, + Shallow => stable_mir::mir::FakeBorrowKind::Shallow, + } + } +} + impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { type T = stable_mir::mir::NullOp; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 112e44f674efb..4abf991fba25d 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -807,7 +807,10 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { | ty::InstanceDef::ThreadLocalShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrShim(..) => stable_mir::mir::mono::InstanceKind::Shim, + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::AsyncDropGlueCtorShim(..) => { + stable_mir::mir::mono::InstanceKind::Shim + } }; stable_mir::mir::mono::Instance { def, kind } } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 8925b7a42d485..1ac3a817bba56 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -6,7 +6,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::Idx; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use std::fmt; use std::hash::{BuildHasherDefault, Hash, Hasher}; diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 78ac61fa31db9..fe09daf522c1c 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -1,7 +1,7 @@ use std::fmt; use std::str::FromStr; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; /// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).) #[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 1df2b357ac128..aa4bcefab9391 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -34,7 +34,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal}; use rustc_data_structures::unhash::UnhashMap; use rustc_index::IndexVec; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cell::RefCell; use std::collections::hash_map::Entry; @@ -459,28 +459,21 @@ impl HygieneData { span } - // We need to walk up and update return span if we meet macro instantiation to be collapsed - fn walk_chain_collapsed( - &self, - mut span: Span, - to: Span, - collapse_debuginfo_feature_enabled: bool, - ) -> Span { + fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span { let orig_span = span; let mut ret_span = span; - - debug!( - "walk_chain_collapsed({:?}, {:?}), feature_enable={}", - span, to, collapse_debuginfo_feature_enabled, - ); + debug!("walk_chain_collapsed({:?}, {:?})", span, to); debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); - while !span.eq_ctxt(to) && span.from_expansion() { - let outer_expn = self.outer_expn(span.ctxt()); + while let ctxt = span.ctxt() + && !ctxt.is_root() + && ctxt != to.ctxt() + { + let outer_expn = self.outer_expn(ctxt); debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn); let expn_data = self.expn_data(outer_expn); debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); span = expn_data.call_site; - if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo { + if expn_data.collapse_debuginfo { ret_span = span; } } @@ -604,14 +597,13 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { HygieneData::with(|data| data.walk_chain(span, to)) } -pub fn walk_chain_collapsed( - span: Span, - to: Span, - collapse_debuginfo_feature_enabled: bool, -) -> Span { - HygieneData::with(|hdata| { - hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled) - }) +/// In order to have good line stepping behavior in debugger, for the given span we return its +/// outermost macro call site that still has a `#[collapse_debuginfo(yes)]` property on it. +/// We also stop walking call sites at the function body level because no line stepping can occur +/// at the level above that. +/// The returned span can then be used in emitted debuginfo. +pub fn walk_chain_collapsed(span: Span, to: Span) -> Span { + HygieneData::with(|data| data.walk_chain_collapsed(span, to)) } pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { @@ -1251,7 +1243,7 @@ struct HygieneDecodeContextInner { // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create // a new id in the global `HygieneData`. This map tracks the ID we end up picking, // so that multiple occurrences of the same serialized id are decoded to the same - // `SyntaxContext`. This only stores `SyntaxContext`s which are completly decoded. + // `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded. remapped_ctxts: Vec>, /// Maps serialized `SyntaxContext` ids that are currently being decoded to a `SyntaxContext`. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f749d4eb83368..f83bacdcebe77 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -35,14 +35,11 @@ extern crate self as rustc_span; -#[macro_use] -extern crate rustc_macros; - #[macro_use] extern crate tracing; use rustc_data_structures::{outline, AtomicRef}; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index e3e76caebaf00..2093dcf0e8315 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -12,9 +12,10 @@ use crate::*; use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, RwLock}; use rustc_data_structures::unhash::UnhashMap; +use rustc_macros::{Decodable, Encodable}; use std::fs; use std::io::{self, BorrowedBuf, Read}; -use std::path::{self}; +use std::path; #[cfg(test)] mod tests; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5eeb3d4ff1f6..7fe94c2e82ba6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -8,7 +8,7 @@ use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; use rustc_data_structures::sync::Lock; -use rustc_macros::HashStable_Generic; +use rustc_macros::{symbols, Decodable, Encodable, HashStable_Generic}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -192,6 +192,7 @@ symbols! { Duration, Encodable, Encoder, + Enumerate, Eq, Equal, Err, @@ -425,6 +426,16 @@ symbols! { async_call_mut, async_call_once, async_closure, + async_destruct, + async_drop, + async_drop_chain, + async_drop_defer, + async_drop_either, + async_drop_fuse, + async_drop_in_place, + async_drop_noop, + async_drop_slice, + async_drop_surface_drop_in_place, async_fn, async_fn_in_trait, async_fn_kind_helper, @@ -743,6 +754,7 @@ symbols! { enable, encode, end, + enumerate_method, env, env_CFG_RELEASE: env!("CFG_RELEASE"), eprint_macro, @@ -826,6 +838,7 @@ symbols! { fadd_fast, fake_variadic, fallback, + fallback_surface_drop, fdiv_algebraic, fdiv_fast, feature, @@ -1337,7 +1350,7 @@ symbols! { panic_misaligned_pointer_dereference, panic_nounwind, panic_runtime, - panic_str, + panic_str_2015, panic_unwind, panicking, param_attrs, @@ -1789,6 +1802,7 @@ symbols! { sub_assign, sub_with_overflow, suggestion, + surface_async_drop_in_place, sym, sync, synthetic, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index f68668a91e688..0ed1f67bb8218 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,12 +1,13 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; - use std::fmt::{self, Write}; use std::mem::{self, discriminant}; +use tracing::debug; pub(super) fn mangle<'tcx>( tcx: TyCtxt<'tcx>, @@ -55,7 +56,9 @@ pub(super) fn mangle<'tcx>( printer .print_def_path( def_id, - if let ty::InstanceDef::DropGlue(_, _) = instance.def { + if let ty::InstanceDef::DropGlue(_, _) | ty::InstanceDef::AsyncDropGlueCtorShim(_, _) = + instance.def + { // Add the name of the dropped type to the symbol name &*instance.args } else { diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index b950947870272..745ae41085b29 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -93,12 +93,6 @@ #![feature(let_chains)] #![allow(internal_features)] -#[macro_use] -extern crate rustc_middle; - -#[macro_use] -extern crate tracing; - use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -107,6 +101,7 @@ use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; +use tracing::debug; mod hashed; mod legacy; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 58b67c77a6150..fc2c3dcb2d952 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -5,6 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::bug; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, PrintError, Printer}; use rustc_middle::ty::{ diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index cdd82aa9dbc92..3ddea42f67bbd 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -1,6 +1,7 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt}; +use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; use std::str::FromStr; @@ -100,6 +101,8 @@ pub use attr_impl::ArgAttribute; #[allow(non_upper_case_globals)] #[allow(unused)] mod attr_impl { + use rustc_macros::HashStable_Generic; + // The subset of llvm::Attribute needed for arguments, packed into a bitfield. #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, HashStable_Generic)] pub struct ArgAttribute(u8); diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 5ae9a2e205818..1a3218da1af04 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -1,7 +1,6 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index f56dbac708b65..37184393a730b 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -1,7 +1,6 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; -use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs index eab38a4a4f4a3..6943fd9b5d72a 100644 --- a/compiler/rustc_target/src/asm/avr.rs +++ b/compiler/rustc_target/src/asm/avr.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs index 9bc94274675d5..faaeabb3c901b 100644 --- a/compiler/rustc_target/src/asm/bpf.rs +++ b/compiler/rustc_target/src/asm/bpf.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs index 64607ee4b81db..db6cdecfe1909 100644 --- a/compiler/rustc_target/src/asm/csky.rs +++ b/compiler/rustc_target/src/asm/csky.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs index 19da7b8084853..7a809efee6f4d 100644 --- a/compiler/rustc_target/src/asm/hexagon.rs +++ b/compiler/rustc_target/src/asm/hexagon.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index 15d0f54ce3b6e..534b696f7edf0 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs index ac94dcc03dc6b..ea367e3d2f94e 100644 --- a/compiler/rustc_target/src/asm/m68k.rs +++ b/compiler/rustc_target/src/asm/m68k.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs index 0ac1a43ae183b..f0d659c9b9796 100644 --- a/compiler/rustc_target/src/asm/mips.rs +++ b/compiler/rustc_target/src/asm/mips.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 49de92b86cb48..5f4ce5ed59974 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -1,7 +1,7 @@ use crate::spec::Target; use crate::{abi::Size, spec::RelocModel}; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::Symbol; use std::fmt; use std::str::FromStr; @@ -24,7 +24,7 @@ macro_rules! def_reg_class { $class:ident, )* }) => { - #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] + #[derive(Copy, Clone, rustc_macros::Encodable, rustc_macros::Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, rustc_macros::HashStable_Generic)] #[allow(non_camel_case_types)] pub enum $arch_regclass { $($class,)* @@ -73,7 +73,7 @@ macro_rules! def_regs { )* }) => { #[allow(unreachable_code)] - #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] + #[derive(Copy, Clone, rustc_macros::Encodable, rustc_macros::Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, rustc_macros::HashStable_Generic)] #[allow(non_camel_case_types)] pub enum $arch_reg { $($reg,)* diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs index 439f3ba0b575b..14013cd8a7b41 100644 --- a/compiler/rustc_target/src/asm/msp430.rs +++ b/compiler/rustc_target/src/asm/msp430.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs index 57aa50fceb88b..6c066ad7ac8fc 100644 --- a/compiler/rustc_target/src/asm/nvptx.rs +++ b/compiler/rustc_target/src/asm/nvptx.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; def_reg_class! { diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 4e8cbe34de948..45e9ace0f291b 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 2505d36f5b8a4..3845a0e14af09 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -1,7 +1,6 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; -use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 6bc668454b191..2bab41cd8a1b4 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs index d13a6131f9ab4..f242faec0266d 100644 --- a/compiler/rustc_target/src/asm/spirv.rs +++ b/compiler/rustc_target/src/asm/spirv.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; def_reg_class! { diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs index eb0b23ef43dd8..b5f4d10fb2b4b 100644 --- a/compiler/rustc_target/src/asm/wasm.rs +++ b/compiler/rustc_target/src/asm/wasm.rs @@ -1,5 +1,4 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; def_reg_class! { diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 3b5da8806ccc2..28413a5bcbd17 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -1,7 +1,6 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; -use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index ba359ac6de130..84d7930663a30 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -20,12 +20,6 @@ use std::path::{Path, PathBuf}; -#[macro_use] -extern crate rustc_macros; - -#[macro_use] -extern crate tracing; - pub mod abi; pub mod asm; pub mod json; diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index 388e76d83e243..bf51bb4bf8256 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -1,6 +1,6 @@ use std::fmt; -use rustc_macros::HashStable_Generic; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 291a761913bf2..bd347c1b4b3fd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -40,6 +40,7 @@ use crate::json::{Json, ToJson}; use crate::spec::abi::Abi; use crate::spec::crt_objects::CrtObjects; use rustc_fs_util::try_canonicalize; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{kw, sym, Symbol}; use serde_json::Value; @@ -50,8 +51,7 @@ use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fmt, io}; - -use rustc_macros::HashStable_Generic; +use tracing::debug; pub mod abi; pub mod crt_objects; diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index b126062102eda..7228a9ba01672 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{ codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, Subdiagnostic, }; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; use rustc_span::{Span, Symbol}; @@ -104,7 +104,7 @@ impl Subdiagnostic for AdjustSignatureBorrow { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0595e82b39ed4..b2400cec42f16 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,10 +1,9 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, ObligationCtxt, SelectionContext}; - -use crate::traits::TraitEngineExt as _; +use crate::traits::{self, ObligationCtxt, SelectionContext, TraitEngineExt as _}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt as _}; +use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; use rustc_middle::traits::query::NoSolution; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index d54f714b22c69..f1f03b810a961 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,7 +17,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(control_flow_enum)] @@ -29,17 +28,10 @@ #![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc -#[macro_use] -extern crate rustc_macros; -#[cfg(target_pointer_width = "64")] -#[macro_use] -extern crate rustc_data_structures; #[macro_use] extern crate tracing; #[macro_use] extern crate rustc_middle; -#[macro_use] -extern crate smallvec; pub mod errors; pub mod infer; diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 222d0b4d5e75d..5e0d7da4f06b1 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,5 +1,6 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; +use rustc_macros::extension; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 8b5c029428cfc..280975f63bd3d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,8 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. -use super::{EvalCtxt, SolverMode}; use crate::solve::GoalSource; -use crate::traits::coherence; +use crate::solve::{inspect, EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::inspect::ProbeKind; @@ -16,6 +15,7 @@ use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use std::fmt::Debug; +use std::mem; pub(super) mod structural_traits; @@ -47,21 +47,23 @@ pub(super) trait GoalKind<'tcx>: /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, + source: CandidateSource, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. - fn consider_implied_clause( + fn probe_and_consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, + source: CandidateSource, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, requirements: impl IntoIterator>>, - ) -> QueryResult<'tcx> { - Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { + ) -> Result, NoSolution> { + Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { // FIXME(-Znext-solver=coinductive): check whether this should be // `GoalSource::ImplWhereBound` for any caller. ecx.add_goals(GoalSource::Misc, requirements); @@ -72,15 +74,16 @@ pub(super) trait GoalKind<'tcx>: /// Consider a clause specifically for a `dyn Trait` self type. This requires /// additionally checking all of the supertraits and object bounds to hold, /// since they're not implied by the well-formedness of the object type. - fn consider_object_bound_candidate( + fn probe_and_consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, + source: CandidateSource, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, - ) -> QueryResult<'tcx> { - Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { + ) -> Result, NoSolution> { + Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { let tcx = ecx.tcx(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { - bug!("expected object type in `consider_object_bound_candidate`"); + bug!("expected object type in `probe_and_consider_object_bound_candidate`"); }; // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? ecx.add_goals( @@ -111,7 +114,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, guar: ErrorGuaranteed, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A type implements an `auto trait` if its components do as well. /// @@ -120,13 +123,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A type is `Sized` if its tail component is `Sized`. /// @@ -135,7 +138,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// @@ -144,20 +147,20 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// family of traits where `A` is given by the signature of the type. @@ -165,7 +168,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// An async closure is known to implement the `AsyncFn` family of traits /// where `A` is given by the signature of the type. @@ -173,7 +176,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// is used internally to delay computation for async closures until after @@ -181,13 +184,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// `Pointee` is always implemented. /// @@ -197,7 +200,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future`, where `O` is given by the coroutine's return type @@ -205,7 +208,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator`, where `O` is given by the generator's yield type @@ -213,19 +216,19 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine`, given the resume, yield, @@ -233,22 +236,27 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; + + fn consider_builtin_async_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> Result, NoSolution>; fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; + ) -> Result, NoSolution>; /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. @@ -260,7 +268,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>; + ) -> Vec>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -276,7 +284,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if normalized_self_ty.is_ty_var() { debug!("self type has been normalized to infer"); - return self.forced_ambiguity(MaybeCause::Ambiguity); + return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } let goal = @@ -309,21 +317,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates } - fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec> { - let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); - let certainty = Certainty::Maybe(cause); + pub(super) fn forced_ambiguity( + &mut self, + cause: MaybeCause, + ) -> Result, NoSolution> { // This may fail if `try_evaluate_added_goals` overflows because it // fails to reach a fixpoint but ends up getting an error after // running for some additional step. // - // FIXME: Add a test for this. It seems to be necessary for typenum but - // is incredibly hard to minimize as it may rely on being inside of a - // trait solver cycle. - let result = self.evaluate_added_goals_and_make_canonical_response(certainty); - let mut dummy_probe = self.inspect.new_probe(); - dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result }); - self.inspect.finish_probe(dummy_probe); - if let Ok(result) = result { vec![Candidate { source, result }] } else { vec![] } + // cc trait-system-refactor-initiative#105 + let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); + let certainty = Certainty::Maybe(cause); + self.probe_trait_candidate(source) + .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty)) } #[instrument(level = "debug", skip_all)] @@ -520,6 +526,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_coroutine_candidate(self, goal) } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { G::consider_builtin_discriminant_kind_candidate(self, goal) + } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + G::consider_builtin_async_destruct_candidate(self, goal) } else if lang_items.destruct_trait() == Some(trait_def_id) { G::consider_builtin_destruct_candidate(self, goal) } else if lang_items.transmute_trait() == Some(trait_def_id) { @@ -528,20 +536,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Err(NoSolution) }; - match result { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }), - Err(NoSolution) => (), - } + candidates.extend(result); // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` if lang_items.unsize_trait() == Some(trait_def_id) { - for (result, source) in G::consider_structural_builtin_unsize_candidates(self, goal) { - candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result }); - } + candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } @@ -552,12 +552,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { - match G::consider_implied_clause(self, goal, assumption, []) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) - } - Err(NoSolution) => (), - } + candidates.extend(G::probe_and_consider_implied_clause( + self, + CandidateSource::ParamEnv(i), + goal, + assumption, + [], + )); } } @@ -643,12 +644,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) { - match G::consider_implied_clause(self, goal, assumption, []) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }); - } - Err(NoSolution) => {} - } + candidates.extend(G::probe_and_consider_implied_clause( + self, + CandidateSource::AliasBound, + goal, + assumption, + [], + )); } if kind != ty::Projection { @@ -723,17 +725,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } ty::ExistentialPredicate::Projection(_) | ty::ExistentialPredicate::AutoTrait(_) => { - match G::consider_object_bound_candidate( + candidates.extend(G::probe_and_consider_object_bound_candidate( self, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, bound.with_self_ty(tcx, self_ty), - ) { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }), - Err(NoSolution) => (), - } + )); } } } @@ -744,15 +741,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| { - match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object { - vtable_base, - }), - result, - }), - Err(NoSolution) => (), - } + candidates.extend(G::probe_and_consider_object_bound_candidate( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }), + goal, + assumption.to_predicate(tcx), + )); }); } } @@ -770,25 +764,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { let tcx = self.tcx(); - let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| { - let trait_ref = goal.predicate.trait_ref(tcx); - let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty); - match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? { - Ok(()) => Err(NoSolution), - Err(_) => { + candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( + |ecx| { + let trait_ref = goal.predicate.trait_ref(tcx); + if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { + Err(NoSolution) + } else { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - } - }); - - match result { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }), - Err(NoSolution) => {} - } + }, + )) } /// If there's a where-bound for the current goal, do not use any impl candidates @@ -806,6 +792,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { + // HACK: We temporarily remove the `ProofTreeBuilder` to + // avoid adding `Trait` candidates to the candidates used + // to prove the current goal. + let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop()); + let tcx = self.tcx(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); @@ -828,6 +819,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { false } CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, + CandidateSource::CoherenceUnknowable => bug!("uh oh"), }); } // If it is still ambiguous we instead just force the whole goal @@ -835,10 +827,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs Certainty::Maybe(cause) => { debug!(?cause, "force ambiguity"); - *candidates = self.forced_ambiguity(cause); + *candidates = self.forced_ambiguity(cause).into_iter().collect(); } } } + self.inspect = inspect; } /// If there are multiple ways to prove a trait or projection goal, we have diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index a778414d9d1bc..a8b1a182d3c23 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -4,6 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::LangItem; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 0b37163d59702..6722abd709c31 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -19,9 +19,12 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::resolve::EagerResolver; +use rustc_infer::infer::type_variable::TypeVariableOrigin; +use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::solve::NestedNormalizationGoals; use rustc_middle::infer::canonical::Canonical; +use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, @@ -29,7 +32,7 @@ use rustc_middle::traits::solve::{ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use std::assert_matches::assert_matches; use std::iter; use std::ops::Deref; @@ -95,6 +98,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { previous call to `try_evaluate_added_goals!`" ); + self.inspect.make_canonical_response(certainty); + // When normalizing, we've replaced the expected term with an unconstrained // inference variable. This means that we dropped information which could // have been important. We handle this by instead returning the nested goals @@ -374,36 +379,70 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } -impl<'tcx> inspect::ProofTreeBuilder<'tcx> { - pub fn make_canonical_state>>( - ecx: &EvalCtxt<'_, 'tcx>, - data: T, - ) -> inspect::CanonicalState<'tcx, T> { - let state = inspect::State { var_values: ecx.var_values, data }; - let state = state.fold_with(&mut EagerResolver::new(ecx.infcx)); - Canonicalizer::canonicalize( - ecx.infcx, - CanonicalizeMode::Response { max_input_universe: ecx.max_input_universe }, - &mut vec![], - state, - ) +/// Used by proof trees to be able to recompute intermediate actions while +/// evaluating a goal. The `var_values` not only include the bound variables +/// of the query input, but also contain all unconstrained inference vars +/// created while evaluating this goal. +pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + var_values: &[ty::GenericArg<'tcx>], + max_input_universe: ty::UniverseIndex, + data: T, +) -> inspect::CanonicalState<'tcx, T> { + let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) }; + let state = inspect::State { var_values, data }; + let state = state.fold_with(&mut EagerResolver::new(infcx)); + Canonicalizer::canonicalize( + infcx, + CanonicalizeMode::Response { max_input_universe }, + &mut vec![], + state, + ) +} + +/// Instantiate a `CanonicalState`. +/// +/// Unlike for query responses, `CanonicalState` also track fresh inference +/// variables created while evaluating a goal. When creating two separate +/// `CanonicalState` during a single evaluation both may reference this +/// fresh inference variable. When instantiating them we now create separate +/// inference variables for it and have to unify them somehow. We do this +/// by extending the `var_values` while building the proof tree. +/// +/// This currently assumes that unifying the var values trivially succeeds. +/// Adding any inference constraints which weren't present when originally +/// computing the canonical query can result in bugs. +pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + span: Span, + param_env: ty::ParamEnv<'tcx>, + orig_values: &mut Vec>, + state: inspect::CanonicalState<'tcx, T>, +) -> T { + // In case any fresh inference variables have been created between `state` + // and the previous instantiation, extend `orig_values` for it. + assert!(orig_values.len() <= state.value.var_values.len()); + for i in orig_values.len()..state.value.var_values.len() { + let unconstrained = match state.value.var_values.var_values[i].unpack() { + ty::GenericArgKind::Lifetime(_) => { + infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + } + ty::GenericArgKind::Type(_) => { + infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }).into() + } + ty::GenericArgKind::Const(ct) => infcx + .next_const_var(ct.ty(), ConstVariableOrigin { param_def_id: None, span }) + .into(), + }; + + orig_values.push(unconstrained); } - /// Instantiate a `CanonicalState`. This assumes that unifying the var values - /// trivially succeeds. Adding any inference constraints which weren't present when - /// originally computing the canonical query can result in bugs. - pub fn instantiate_canonical_state>>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - state: inspect::CanonicalState<'tcx, T>, - ) -> T { - let instantiation = - EvalCtxt::compute_query_response_instantiation_values(infcx, original_values, &state); + let instantiation = + EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); - let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); + let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); - EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values); - data - } + EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); + data } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index f914e6b3f2e8e..1710746ae504e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -9,6 +9,7 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; +use rustc_macros::{extension, HashStable}; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::solve::inspect; @@ -26,6 +27,7 @@ use rustc_span::DUMMY_SP; use std::io::Write; use std::ops::ControlFlow; +use crate::traits::coherence; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; @@ -34,7 +36,7 @@ use super::{search_graph::SearchGraph, Goal}; use super::{GoalSource, SolverMode}; pub use select::InferCtxtSelectExt; -mod canonical; +pub(super) mod canonical; mod probe; mod select; @@ -84,7 +86,7 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, - pub(super) nested_goals: NestedGoals<'tcx>, + nested_goals: NestedGoals<'tcx>, // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`? // @@ -161,7 +163,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). - fn enter_root( + pub(super) fn enter_root( infcx: &InferCtxt<'tcx>, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R, @@ -242,7 +244,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { search_graph, nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: canonical_goal_evaluation.new_goal_evaluation_step(input), + inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values, input), }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { @@ -255,7 +257,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } let result = f(&mut ecx, input.goal); - + ecx.inspect.probe_final_state(ecx.infcx, ecx.max_input_universe); canonical_goal_evaluation.goal_evaluation_step(ecx.inspect); // When creating a query response we clone the opaque type constraints @@ -338,7 +340,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// storage. // FIXME(-Znext-solver=coinduction): `_source` is currently unused but will // be necessary once we implement the new coinduction approach. - fn evaluate_goal_raw( + pub(super) fn evaluate_goal_raw( &mut self, goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, @@ -458,13 +460,23 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] + pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.nested_goals.normalizes_to_goals.push(goal); + } + + #[instrument(level = "debug", skip(self))] + pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.nested_goals.goals.push((source, goal)); + } + // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning // the certainty of all the goals. #[instrument(level = "debug", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result { - let inspect = self.inspect.new_evaluate_added_goals(); - let inspect = core::mem::replace(&mut self.inspect, inspect); - + self.inspect.start_evaluate_added_goals(); let mut response = Ok(Certainty::overflow(false)); for _ in 0..FIXPOINT_STEP_LIMIT { // FIXME: This match is a bit ugly, it might be nice to change the inspect @@ -482,15 +494,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - self.inspect.eval_added_goals_result(response); + self.inspect.evaluate_added_goals_result(response); if response.is_err() { self.tainted = Err(NoSolution); } - let goal_evaluations = std::mem::replace(&mut self.inspect, inspect); - self.inspect.added_goals_evaluation(goal_evaluations); - response } @@ -499,10 +508,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { let tcx = self.tcx(); + self.inspect.start_evaluate_added_goals_step(); let mut goals = core::mem::take(&mut self.nested_goals); - self.inspect.evaluate_added_goals_loop_start(); - // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for goal in goals.normalizes_to_goals { @@ -586,17 +594,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.infcx.tcx } - pub(super) fn next_ty_infer(&self) -> Ty<'tcx> { - self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }) + pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { + let ty = self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }); + self.inspect.add_var_value(ty); + ty } - pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { - self.infcx.next_const_var(ty, ConstVariableOrigin { param_def_id: None, span: DUMMY_SP }) + pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> { + let ct = self + .infcx + .next_const_var(ty, ConstVariableOrigin { param_def_id: None, span: DUMMY_SP }); + self.inspect.add_var_value(ct); + ct } /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. /// If `kind` is an integer inference variable this will still return a ty infer var. - pub(super) fn next_term_infer_of_kind(&self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { + pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { match kind.unpack() { ty::TermKind::Ty(_) => self.next_ty_infer().into(), ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), @@ -929,6 +943,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + pub(super) fn trait_ref_is_knowable( + &mut self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + ) -> Result { + let infcx = self.infcx; + let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); + coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) + .map(|is_knowable| is_knowable.is_ok()) + } + pub(super) fn can_define_opaque_ty(&self, def_id: impl Into) -> bool { self.infcx.can_define_opaque_ty(def_id) } @@ -986,19 +1011,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if candidate_key.def_id != key.def_id { continue; } - values.extend(self.probe_misc_candidate("opaque type storage").enter(|ecx| { - for (a, b) in std::iter::zip(candidate_key.args, key.args) { - ecx.eq(param_env, a, b)?; - } - ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.to_def_id(), - candidate_key.args, - param_env, - candidate_ty, - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - })); + values.extend( + self.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup { + result: *result, + }) + .enter(|ecx| { + for (a, b) in std::iter::zip(candidate_key.args, key.args) { + ecx.eq(param_env, a, b)?; + } + ecx.eq(param_env, candidate_ty, ty)?; + ecx.add_item_bounds_for_hidden_type( + candidate_key.def_id.to_def_id(), + candidate_key.args, + param_env, + candidate_ty, + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ); } values } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 5b1124e8b9fcb..ee23f49939b7c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -1,6 +1,7 @@ use crate::solve::assembly::Candidate; use super::EvalCtxt; +use rustc_infer::traits::BuiltinImplSource; use rustc_middle::traits::{ query::NoSolution, solve::{inspect, CandidateSource, QueryResult}, @@ -20,23 +21,29 @@ where pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; + let infcx = outer_ecx.infcx; + let max_input_universe = outer_ecx.max_input_universe; let mut nested_ecx = EvalCtxt { - infcx: outer_ecx.infcx, + infcx, variables: outer_ecx.variables, var_values: outer_ecx.var_values, is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal, predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, - max_input_universe: outer_ecx.max_input_universe, + max_input_universe, search_graph: outer_ecx.search_graph, nested_goals: outer_ecx.nested_goals.clone(), tainted: outer_ecx.tainted, - inspect: outer_ecx.inspect.new_probe(), + inspect: outer_ecx.inspect.take_and_enter_probe(), }; - let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx)); - if !outer_ecx.inspect.is_noop() { + let r = nested_ecx.infcx.probe(|_| { + let r = f(&mut nested_ecx); + nested_ecx.inspect.probe_final_state(infcx, max_input_universe); + r + }); + if !nested_ecx.inspect.is_noop() { let probe_kind = probe_kind(&r); nested_ecx.inspect.probe_kind(probe_kind); - outer_ecx.inspect.finish_probe(nested_ecx.inspect); + outer_ecx.inspect = nested_ecx.inspect.finish_probe(); } r } @@ -69,24 +76,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } } - pub(in crate::solve) fn probe_misc_candidate( + pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, - name: &'static str, - ) -> ProbeCtxt< - '_, - 'a, - 'tcx, - impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>, - QueryResult<'tcx>, - > { - ProbeCtxt { - ecx: self, - probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::MiscCandidate { - name, - result: *result, - }, - _result: PhantomData, - } + source: BuiltinImplSource, + ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>> + { + self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 6644d3c77afd9..16fe045b82de7 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -1,21 +1,17 @@ -use rustc_hir as hir; +use std::ops::ControlFlow; + use rustc_hir::def_id::DefId; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::traits::solve::inspect::ProbeKind; +use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_infer::traits::{ - Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine, -}; -use rustc_middle::traits::solve::{CandidateSource, CanonicalInput, Certainty, Goal}; -use rustc_middle::traits::{ - BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError, + BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause, + PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; +use rustc_macros::extension; +use rustc_span::Span; -use crate::solve::assembly::Candidate; -use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree}; -use crate::solve::inspect::ProofTreeBuilder; -use crate::traits::StructurallyNormalizeExt; -use crate::traits::TraitEngineExt; +use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; #[extension(pub trait InferCtxtSelectExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { @@ -25,357 +21,192 @@ impl<'tcx> InferCtxt<'tcx> { ) -> SelectionResult<'tcx, Selection<'tcx>> { assert!(self.next_trait_solver()); - self.enter_forall(obligation.predicate, |pred| { - let trait_goal = Goal::new(self.tcx, obligation.param_env, pred); - - let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| { - let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate); - let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal); - let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal); + self.visit_proof_tree( + Goal::new(self.tcx, obligation.param_env, obligation.predicate), + &mut Select { span: obligation.cause.span }, + ) + .break_value() + .unwrap() + } +} - // pseudo-winnow - if candidates.len() == 0 { - return Err(SelectionError::Unimplemented); - } else if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { - candidate_should_be_dropped_in_favor_of( - ecx.tcx(), - &candidates[i], - &candidates[j], - ) - }); - if should_drop_i { - candidates.swap_remove(i); - } else { - i += 1; - if i > 1 { - return Ok(None); - } - } - } - } +struct Select { + span: Span, +} - let candidate = candidates.pop().unwrap(); - let (normalization_nested_goals, certainty) = ecx - .instantiate_and_apply_query_response( - trait_goal.param_env, - orig_values, - candidate.result, - ); - assert!(normalization_nested_goals.is_empty()); - Ok(Some((candidate, certainty))) - }); +impl<'tcx> inspect::ProofTreeVisitor<'tcx> for Select { + type Result = ControlFlow>>; - let (candidate, certainty) = match result { - Ok(Some(result)) => result, - Ok(None) => return Ok(None), - Err(e) => return Err(e), - }; + fn span(&self) -> Span { + self.span + } - let goal = self.resolve_vars_if_possible(trait_goal); - match (certainty, candidate.source) { - // Rematching the implementation will instantiate the same nested goals that - // would have caused the ambiguity, so we can still make progress here regardless. - (_, CandidateSource::Impl(def_id)) => rematch_impl(self, goal, def_id), + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + let mut candidates = goal.candidates(); + candidates.retain(|cand| cand.result().is_ok()); - // If an unsize goal is ambiguous, then we can manually rematch it to make - // selection progress for coercion during HIR typeck. If it is *not* ambiguous, - // but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals, - // and we need to rematch those to detect tuple unsizing and trait upcasting. - // FIXME: This will be wrong if we have param-env or where-clause bounds - // with the unsize goal -- we may need to mark those with different impl - // sources. - (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src)) - | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc)) - if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => - { - rematch_unsize(self, goal, src, certainty) - } + // No candidates -- not implemented. + if candidates.is_empty() { + return ControlFlow::Break(Err(SelectionError::Unimplemented)); + } - // Technically some builtin impls have nested obligations, but if - // `Certainty::Yes`, then they should've all been verified and don't - // need re-checking. - (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => { - Ok(Some(ImplSource::Builtin(src, vec![]))) - } + // One candidate, no need to winnow. + if candidates.len() == 1 { + return ControlFlow::Break(Ok(to_selection( + self.span, + candidates.into_iter().next().unwrap(), + ))); + } - // It's fine not to do anything to rematch these, since there are no - // nested obligations. - (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { - Ok(Some(ImplSource::Param(vec![]))) + // We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`. + let mut i = 0; + while i < candidates.len() { + let should_drop_i = (0..candidates.len()) + .filter(|&j| i != j) + .any(|j| candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])); + if should_drop_i { + candidates.swap_remove(i); + } else { + i += 1; + if i > 1 { + return ControlFlow::Break(Ok(None)); } - - (Certainty::Maybe(_), _) => Ok(None), } - }) - } -} + } -impl<'tcx> EvalCtxt<'_, 'tcx> { - fn compute_canonical_trait_candidates( - &mut self, - canonical_input: CanonicalInput<'tcx>, - ) -> Vec> { - // This doesn't record the canonical goal on the stack during the - // candidate assembly step, but that's fine. Selection is conceptually - // outside of the solver, and if there were any cycles, we'd encounter - // the cycle anyways one step later. - EvalCtxt::enter_canonical( - self.tcx(), - self.search_graph, - canonical_input, - // FIXME: This is wrong, idk if we even want to track stuff here. - &mut ProofTreeBuilder::new_noop(), - |ecx, goal| { - let trait_goal = Goal { - param_env: goal.param_env, - predicate: goal - .predicate - .to_opt_poly_trait_pred() - .expect("we canonicalized a trait goal") - .no_bound_vars() - .expect("we instantiated all bound vars"), - }; - ecx.assemble_and_evaluate_candidates(trait_goal) - }, - ) + ControlFlow::Break(Ok(to_selection(self.span, candidates.into_iter().next().unwrap()))) } } +/// This is a lot more limited than the old solver's equivalent method. This may lead to more `Ok(None)` +/// results when selecting traits in polymorphic contexts, but we should never rely on the lack of ambiguity, +/// and should always just gracefully fail here. We shouldn't rely on this incompleteness. fn candidate_should_be_dropped_in_favor_of<'tcx>( - tcx: TyCtxt<'tcx>, - victim: &Candidate<'tcx>, - other: &Candidate<'tcx>, + victim: &inspect::InspectCandidate<'_, 'tcx>, + other: &inspect::InspectCandidate<'_, 'tcx>, ) -> bool { - match (victim.source, other.source) { - (CandidateSource::ParamEnv(victim_idx), CandidateSource::ParamEnv(other_idx)) => { - victim_idx >= other_idx + // Don't winnow until `Certainty::Yes` -- we don't need to winnow until + // codegen, technically. + if matches!(other.result().unwrap(), Certainty::Maybe(..)) { + return false; + } + + let inspect::ProbeKind::TraitCandidate { source: victim_source, result: _ } = victim.kind() + else { + return false; + }; + let inspect::ProbeKind::TraitCandidate { source: other_source, result: _ } = other.kind() + else { + return false; + }; + + match (victim_source, other_source) { + (_, CandidateSource::CoherenceUnknowable) | (CandidateSource::CoherenceUnknowable, _) => { + bug!("should not have assembled a CoherenceUnknowable candidate") } - (_, CandidateSource::ParamEnv(_)) => true, - // FIXME: we could prefer earlier vtable bases perhaps... + // Prefer dyn candidates over non-dyn candidates. This is necessary to + // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. ( CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), ) => false, - (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. })) => true, + ( + CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound, + CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), + ) => true, + // Prefer specializing candidates over specialized candidates. (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => { - tcx.specializes((other_def_id, victim_def_id)) - && other.result.value.certainty == Certainty::Yes + victim.goal().infcx().tcx.specializes((other_def_id, victim_def_id)) } _ => false, } } +fn to_selection<'tcx>( + span: Span, + cand: inspect::InspectCandidate<'_, 'tcx>, +) -> Option> { + if let Certainty::Maybe(..) = cand.shallow_certainty() { + return None; + } + + let make_nested = || { + cand.instantiate_nested_goals(span) + .into_iter() + .map(|nested| { + Obligation::new( + nested.infcx().tcx, + ObligationCause::dummy_with_span(span), + nested.goal().param_env, + nested.goal().predicate, + ) + }) + .collect() + }; + + Some(match cand.kind() { + ProbeKind::TraitCandidate { source, result: _ } => match source { + CandidateSource::Impl(impl_def_id) => { + // FIXME: Remove this in favor of storing this in the tree + // For impl candidates, we do the rematch manually to compute the args. + ImplSource::UserDefined(rematch_impl(cand.goal(), impl_def_id, span)) + } + CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, make_nested()), + CandidateSource::ParamEnv(_) => ImplSource::Param(make_nested()), + CandidateSource::AliasBound => { + ImplSource::Builtin(BuiltinImplSource::Misc, make_nested()) + } + CandidateSource::CoherenceUnknowable => { + span_bug!(span, "didn't expect to select an unknowable candidate") + } + }, + ProbeKind::TryNormalizeNonRigid { result: _ } + | ProbeKind::NormalizedSelfTyAssembly + | ProbeKind::UnsizeAssembly + | ProbeKind::UpcastProjectionCompatibility + | ProbeKind::OpaqueTypeStorageLookup { result: _ } + | ProbeKind::Root { result: _ } => { + span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind()) + } + }) +} + fn rematch_impl<'tcx>( - infcx: &InferCtxt<'tcx>, - goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, + goal: &inspect::InspectGoal<'_, 'tcx>, impl_def_id: DefId, -) -> SelectionResult<'tcx, Selection<'tcx>> { - let args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + span: Span, +) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + let infcx = goal.infcx(); + let goal_trait_ref = infcx + .enter_forall_and_leak_universe(goal.goal().predicate.to_opt_poly_trait_pred().unwrap()) + .trait_ref; + + let args = infcx.fresh_args_for_item(span, impl_def_id); let impl_trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args); - let mut nested = infcx - .at(&ObligationCause::dummy(), goal.param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, goal.predicate.trait_ref, impl_trait_ref) - .map_err(|_| SelectionError::Unimplemented)? - .into_obligations(); + let InferOk { value: (), obligations: mut nested } = infcx + .at(&ObligationCause::dummy_with_span(span), goal.goal().param_env) + .eq(DefineOpaqueTypes::Yes, goal_trait_ref, impl_trait_ref) + .expect("rematching impl failed"); + + // FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually. nested.extend( infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( - |(pred, _)| Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred), - ), - ); - - Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested }))) -} - -/// The `Unsize` trait is particularly important to coercion, so we try rematch it. -/// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait -/// goal assembly in the solver, both for soundness and in order to avoid ICEs. -fn rematch_unsize<'tcx>( - infcx: &InferCtxt<'tcx>, - goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, - source: BuiltinImplSource, - certainty: Certainty, -) -> SelectionResult<'tcx, Selection<'tcx>> { - let tcx = infcx.tcx; - let mut nested = vec![]; - let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested); - let b_ty = structurally_normalize( - goal.predicate.trait_ref.args.type_at(1), - infcx, - goal.param_env, - &mut nested, - ); - - match (a_ty.kind(), b_ty.kind()) { - // Don't try to coerce `?0` to `dyn Trait` - (ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => Ok(None), - // Stall any ambiguous upcasting goals, since we can't rematch those - (ty::Dynamic(_, _, ty::Dyn), ty::Dynamic(_, _, ty::Dyn)) => match certainty { - Certainty::Yes => Ok(Some(ImplSource::Builtin(source, nested))), - _ => Ok(None), - }, - // `T` -> `dyn Trait` upcasting - (_, &ty::Dynamic(data, region, ty::Dyn)) => { - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - nested.extend(data.iter().map(|pred| { + |(clause, _)| { Obligation::new( infcx.tcx, - ObligationCause::dummy(), - goal.param_env, - pred.with_self_ty(tcx, a_ty), + ObligationCause::dummy_with_span(span), + goal.goal().param_env, + clause, ) - })); - // The type must be Sized to be unsized. - let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, None); - nested.push(Obligation::new( - infcx.tcx, - ObligationCause::dummy(), - goal.param_env, - ty::TraitRef::new(tcx, sized_def_id, [a_ty]), - )); - // The type must outlive the lifetime of the `dyn` we're unsizing into. - nested.push(Obligation::new( - infcx.tcx, - ObligationCause::dummy(), - goal.param_env, - ty::OutlivesPredicate(a_ty, region), - )); - - Ok(Some(ImplSource::Builtin(source, nested))) - } - // `[T; n]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { - nested.extend( - infcx - .at(&ObligationCause::dummy(), goal.param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, a_elem_ty, b_elem_ty) - .expect("expected rematch to succeed") - .into_obligations(), - ); - - Ok(Some(ImplSource::Builtin(source, nested))) - } - // Struct unsizing `Struct` -> `Struct` where `T: Unsize` - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) - if a_def.is_struct() && a_def.did() == b_def.did() => - { - let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); - // We must be unsizing some type parameters. This also implies - // that the struct has a tail field. - if unsizing_params.is_empty() { - bug!("expected rematch to succeed") - } - - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); - let tail_field_ty = tcx.type_of(tail_field.did); - - let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); - let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); - - // Instantiate just the unsizing params from B into A. The type after - // this instantiation must be equal to B. This is so we don't unsize - // unrelated type parameters. - let new_a_args = tcx.mk_args_from_iter( - a_args - .iter() - .enumerate() - .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }), - ); - let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_args); - - nested.extend( - infcx - .at(&ObligationCause::dummy(), goal.param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty) - .expect("expected rematch to succeed") - .into_obligations(), - ); - - // Finally, we require that `TailA: Unsize` for the tail field - // types. - nested.push(Obligation::new( - tcx, - ObligationCause::dummy(), - goal.param_env, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), - )); - - Ok(Some(ImplSource::Builtin(source, nested))) - } - // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) - if a_tys.len() == b_tys.len() && !a_tys.is_empty() => - { - let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); - let b_last_ty = b_tys.last().unwrap(); - - // Instantiate just the tail field of B., and require that they're equal. - let unsized_a_ty = - Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied()); - nested.extend( - infcx - .at(&ObligationCause::dummy(), goal.param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty) - .expect("expected rematch to succeed") - .into_obligations(), - ); - - // Similar to ADTs, require that we can unsize the tail. - nested.push(Obligation::new( - tcx, - ObligationCause::dummy(), - goal.param_env, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), - )); - - // We need to be able to detect tuple unsizing to require its feature gate. - assert_eq!( - source, - BuiltinImplSource::TupleUnsizing, - "compiler-errors wants to know if this can ever be triggered..." - ); - Ok(Some(ImplSource::Builtin(source, nested))) - } - _ => { - assert_ne!(certainty, Certainty::Yes); - Ok(None) - } - } -} + }, + ), + ); -fn structurally_normalize<'tcx>( - ty: Ty<'tcx>, - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - nested: &mut Vec>, -) -> Ty<'tcx> { - if matches!(ty.kind(), ty::Alias(..)) { - let mut engine = >::new(infcx); - let normalized_ty = infcx - .at(&ObligationCause::dummy(), param_env) - .structurally_normalize(ty, &mut *engine) - .expect("normalization shouldn't fail if we got to here"); - nested.extend(engine.pending_obligations()); - normalized_ty - } else { - ty - } + ImplSourceUserDefinedData { impl_def_id, nested, args } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 56c32d3d53916..7c6dd4d3febc9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -11,35 +11,94 @@ use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; -use rustc_infer::infer::InferCtxt; +use rustc_infer::infer::resolve::EagerResolver; +use rustc_infer::infer::type_variable::TypeVariableOrigin; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::traits::{TraitEngine, TraitEngineExt}; +use rustc_macros::extension; +use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty; +use rustc_middle::ty::TypeFoldable; +use rustc_span::{Span, DUMMY_SP}; -use crate::solve::inspect::ProofTreeBuilder; +use crate::solve::eval_ctxt::canonical; +use crate::solve::FulfillmentCtxt; +use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource}; use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; +pub struct InspectConfig { + pub max_depth: usize, +} + pub struct InspectGoal<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, depth: usize, - orig_values: &'a [ty::GenericArg<'tcx>], + orig_values: Vec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, - evaluation: &'a inspect::GoalEvaluation<'tcx>, + result: Result, + evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>, + normalizes_to_term_hack: Option>, +} + +/// The expected term of a `NormalizesTo` goal gets replaced +/// with an unconstrained inference variable when computing +/// `NormalizesTo` goals and we return the nested goals to the +/// caller, who also equates the actual term with the expected. +/// +/// This is an implementation detail of the trait solver and +/// not something we want to leak to users. We therefore +/// treat `NormalizesTo` goals as if they apply the expected +/// type at the end of each candidate. +#[derive(Copy, Clone)] +struct NormalizesToTermHack<'tcx> { + term: ty::Term<'tcx>, + unconstrained_term: ty::Term<'tcx>, +} + +impl<'tcx> NormalizesToTermHack<'tcx> { + /// Relate the `term` with the new `unconstrained_term` created + /// when computing the proof tree for this `NormalizesTo` goals. + /// This handles nested obligations. + fn constrain( + self, + infcx: &InferCtxt<'tcx>, + span: Span, + param_env: ty::ParamEnv<'tcx>, + ) -> Result { + infcx + .at(&ObligationCause::dummy_with_span(span), param_env) + .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term) + .map_err(|_| NoSolution) + .and_then(|InferOk { value: (), obligations }| { + let mut fulfill_cx = FulfillmentCtxt::new(infcx); + fulfill_cx.register_predicate_obligations(infcx, obligations); + if fulfill_cx.select_where_possible(infcx).is_empty() { + if fulfill_cx.pending_obligations().is_empty() { + Ok(Certainty::Yes) + } else { + Ok(Certainty::AMBIGUOUS) + } + } else { + Err(NoSolution) + } + }) + } } pub struct InspectCandidate<'a, 'tcx> { goal: &'a InspectGoal<'a, 'tcx>, kind: inspect::ProbeKind<'tcx>, nested_goals: Vec>>>, + final_state: inspect::CanonicalState<'tcx, ()>, result: QueryResult<'tcx>, + shallow_certainty: Certainty, } impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { - pub fn infcx(&self) -> &'a InferCtxt<'tcx> { - self.goal.infcx - } - pub fn kind(&self) -> inspect::ProbeKind<'tcx> { self.kind } @@ -48,55 +107,112 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.result.map(|c| c.value.certainty) } - /// Visit the nested goals of this candidate. + pub fn goal(&self) -> &'a InspectGoal<'a, 'tcx> { + self.goal + } + + /// Certainty passed into `evaluate_added_goals_and_make_canonical_response`. /// - /// FIXME(@lcnr): we have to slightly adapt this API - /// to also use it to compute the most relevant goal - /// for fulfillment errors. Will do that once we actually - /// need it. - pub fn visit_nested>(&self, visitor: &mut V) -> V::Result { - // HACK: An arbitrary cutoff to avoid dealing with overflow and cycles. - if self.goal.depth <= 10 { - let infcx = self.goal.infcx; - infcx.probe(|_| { - let mut instantiated_goals = vec![]; - for goal in &self.nested_goals { - let goal = ProofTreeBuilder::instantiate_canonical_state( - infcx, - self.goal.goal.param_env, - self.goal.orig_values, - *goal, - ); - instantiated_goals.push(goal); - } + /// If this certainty is `Yes`, then we must be confident that the candidate + /// must hold iff it's nested goals hold. This is not true if the certainty is + /// `Maybe(..)`, which suggests we forced ambiguity instead. + /// + /// This is *not* the certainty of the candidate's full nested evaluation, which + /// can be accessed with [`Self::result`] instead. + pub fn shallow_certainty(&self) -> Certainty { + self.shallow_certainty + } + + /// Visit all nested goals of this candidate without rolling + /// back their inference constraints. This function modifies + /// the state of the `infcx`. + pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result { + if self.goal.depth < visitor.config().max_depth { + for goal in self.instantiate_nested_goals(visitor.span()) { + try_visit!(visitor.visit_goal(&goal)); + } + } - for goal in instantiated_goals.iter().copied() { - // We need to be careful with `NormalizesTo` goals as the - // expected term has to be replaced with an unconstrained - // inference variable. - if let Some(kind) = goal.predicate.kind().no_bound_vars() - && let ty::PredicateKind::NormalizesTo(predicate) = kind - && !predicate.alias.is_opaque(infcx.tcx) - { - // FIXME: We currently skip these goals as - // `fn evaluate_root_goal` ICEs if there are any - // `NestedNormalizationGoals`. - continue; + V::Result::output() + } + + /// Instantiate the nested goals for the candidate without rolling back their + /// inference constraints. This function modifies the state of the `infcx`. + pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.to_vec(); + let instantiated_goals: Vec<_> = self + .nested_goals + .iter() + .map(|goal| { + canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + *goal, + ) + }) + .collect(); + + let () = canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + ); + + if let Some(term_hack) = self.goal.normalizes_to_term_hack { + // FIXME: We ignore the expected term of `NormalizesTo` goals + // when computing the result of its candidates. This is + // scuffed. + let _ = term_hack.constrain(infcx, span, param_env); + } + + instantiated_goals + .into_iter() + .map(|goal| match goal.predicate.kind().no_bound_vars() { + Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { + let unconstrained_term = match term.unpack() { + ty::TermKind::Ty(_) => infcx + .next_ty_var(TypeVariableOrigin { param_def_id: None, span }) + .into(), + ty::TermKind::Const(ct) => infcx + .next_const_var( + ct.ty(), + ConstVariableOrigin { param_def_id: None, span }, + ) + .into(), }; - let (_, proof_tree) = infcx.evaluate_root_goal(goal, GenerateProofTree::Yes); - let proof_tree = proof_tree.unwrap(); - try_visit!(visitor.visit_goal(&InspectGoal::new( + let goal = + goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); + let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { + ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + .1; + InspectGoal::new( infcx, self.goal.depth + 1, - &proof_tree, - ))); + proof_tree.unwrap(), + Some(NormalizesToTermHack { term, unconstrained_term }), + ) } - - V::Result::output() + _ => InspectGoal::new( + infcx, + self.goal.depth + 1, + infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(), + None, + ), }) - } else { - V::Result::output() - } + .collect() + } + + /// Visit all nested goals of this candidate, rolling back + /// all inference constraints. + pub fn visit_nested_in_probe>(&self, visitor: &mut V) -> V::Result { + self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor)) } } @@ -110,7 +226,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { } pub fn result(&self) -> Result { - self.evaluation.evaluation.result.map(|c| c.value.certainty) + self.result } fn candidates_recur( @@ -119,6 +235,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { nested_goals: &mut Vec>>>, probe: &inspect::Probe<'tcx>, ) { + let mut shallow_certainty = None; for step in &probe.steps { match step { &inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal), @@ -130,6 +247,9 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.candidates_recur(candidates, nested_goals, probe); nested_goals.truncate(num_goals); } + inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { + assert_eq!(shallow_certainty.replace(*c), None); + } inspect::ProbeStep::EvaluateGoals(_) => (), } } @@ -138,42 +258,36 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly | inspect::ProbeKind::UpcastProjectionCompatibility => (), - // We add a candidate for the root evaluation if there + + // We add a candidate even for the root evaluation if there // is only one way to prove a given goal, e.g. for `WellFormed`. - // - // FIXME: This is currently wrong if we don't even try any - // candidates, e.g. for a trait goal, as in this case `candidates` is - // actually supposed to be empty. - inspect::ProbeKind::Root { result } => { - if candidates.is_empty() { + inspect::ProbeKind::Root { result } + | inspect::ProbeKind::TryNormalizeNonRigid { result } + | inspect::ProbeKind::TraitCandidate { source: _, result } + | inspect::ProbeKind::OpaqueTypeStorageLookup { result } => { + // We only add a candidate if `shallow_certainty` was set, which means + // that we ended up calling `evaluate_added_goals_and_make_canonical_response`. + if let Some(shallow_certainty) = shallow_certainty { candidates.push(InspectCandidate { goal: self, kind: probe.kind, nested_goals: nested_goals.clone(), + final_state: probe.final_state, result, + shallow_certainty, }); } } - inspect::ProbeKind::TryNormalizeNonRigid { result } - | inspect::ProbeKind::MiscCandidate { name: _, result } - | inspect::ProbeKind::TraitCandidate { source: _, result } => { - candidates.push(InspectCandidate { - goal: self, - kind: probe.kind, - nested_goals: nested_goals.clone(), - result, - }); - } } } pub fn candidates(&'a self) -> Vec> { let mut candidates = vec![]; - let last_eval_step = match self.evaluation.evaluation.kind { + let last_eval_step = match self.evaluation_kind { inspect::CanonicalGoalEvaluationKind::Overflow | inspect::CanonicalGoalEvaluationKind::CycleInStack | inspect::CanonicalGoalEvaluationKind::ProvisionalCacheHit => { - warn!("unexpected root evaluation: {:?}", self.evaluation); + warn!("unexpected root evaluation: {:?}", self.evaluation_kind); return vec![]; } inspect::CanonicalGoalEvaluationKind::Evaluation { revisions } => { @@ -191,20 +305,44 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates } + /// Returns the single candidate applicable for the current goal, if it exists. + /// + /// Returns `None` if there are either no or multiple applicable candidates. + pub fn unique_applicable_candidate(&'a self) -> Option> { + // FIXME(-Znext-solver): This does not handle impl candidates + // hidden by env candidates. + let mut candidates = self.candidates(); + candidates.retain(|c| c.result().is_ok()); + candidates.pop().filter(|_| candidates.is_empty()) + } + fn new( infcx: &'a InferCtxt<'tcx>, depth: usize, - root: &'a inspect::GoalEvaluation<'tcx>, + root: inspect::GoalEvaluation<'tcx>, + normalizes_to_term_hack: Option>, ) -> Self { - match root.kind { - inspect::GoalEvaluationKind::Root { ref orig_values } => InspectGoal { - infcx, - depth, - orig_values, - goal: infcx.resolve_vars_if_possible(root.uncanonicalized_goal), - evaluation: root, - }, - inspect::GoalEvaluationKind::Nested { .. } => unreachable!(), + let inspect::GoalEvaluation { uncanonicalized_goal, kind, evaluation } = root; + let inspect::GoalEvaluationKind::Root { orig_values } = kind else { unreachable!() }; + + let result = evaluation.result.and_then(|ok| { + if let Some(term_hack) = normalizes_to_term_hack { + infcx + .probe(|_| term_hack.constrain(infcx, DUMMY_SP, uncanonicalized_goal.param_env)) + .map(|certainty| ok.value.certainty.unify_with(certainty)) + } else { + Ok(ok.value.certainty) + } + }); + + InspectGoal { + infcx, + depth, + orig_values, + goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), + result, + evaluation_kind: evaluation.kind, + normalizes_to_term_hack, } } } @@ -213,6 +351,12 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { pub trait ProofTreeVisitor<'tcx> { type Result: VisitorResult = (); + fn span(&self) -> Span; + + fn config(&self) -> InspectConfig { + InspectConfig { max_depth: 10 } + } + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result; } @@ -223,10 +367,8 @@ impl<'tcx> InferCtxt<'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V, ) -> V::Result { - self.probe(|_| { - let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); - let proof_tree = proof_tree.unwrap(); - visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree)) - }) + let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); + let proof_tree = proof_tree.unwrap(); + visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree, None)) } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 43c76cc5f4a00..466d0d8006018 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -5,6 +5,8 @@ //! see the comment on [ProofTreeBuilder]. use std::mem; +use rustc_infer::infer::InferCtxt; +use rustc_middle::infer::canonical::CanonicalVarValues; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, @@ -12,7 +14,8 @@ use rustc_middle::traits::solve::{ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; -use crate::solve::{self, inspect, EvalCtxt, GenerateProofTree}; +use crate::solve::eval_ctxt::canonical; +use crate::solve::{self, inspect, GenerateProofTree}; /// The core data structure when building proof trees. /// @@ -47,9 +50,7 @@ enum DebugSolver<'tcx> { Root, GoalEvaluation(WipGoalEvaluation<'tcx>), CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>), - AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>), GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), - Probe(WipProbe<'tcx>), } impl<'tcx> From> for DebugSolver<'tcx> { @@ -64,24 +65,12 @@ impl<'tcx> From> for DebugSolver<'tcx> { } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipAddedGoalsEvaluation<'tcx>) -> DebugSolver<'tcx> { - DebugSolver::AddedGoalsEvaluation(g) - } -} - impl<'tcx> From> for DebugSolver<'tcx> { fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> { DebugSolver::GoalEvaluationStep(g) } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(p: WipProbe<'tcx>) -> DebugSolver<'tcx> { - DebugSolver::Probe(p) - } -} - #[derive(Eq, PartialEq, Debug)] struct WipGoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -184,12 +173,41 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> { #[derive(Eq, PartialEq, Debug)] struct WipGoalEvaluationStep<'tcx> { + /// Unlike `EvalCtxt::var_values`, we append a new + /// generic arg here whenever we create a new inference + /// variable. + /// + /// This is necessary as we otherwise don't unify these + /// vars when instantiating multiple `CanonicalState`. + var_values: Vec>, instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, - + probe_depth: usize, evaluation: WipProbe<'tcx>, } impl<'tcx> WipGoalEvaluationStep<'tcx> { + fn current_evaluation_scope(&mut self) -> &mut WipProbe<'tcx> { + let mut current = &mut self.evaluation; + for _ in 0..self.probe_depth { + match current.steps.last_mut() { + Some(WipProbeStep::NestedProbe(p)) => current = p, + _ => bug!(), + } + } + current + } + + fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<'tcx> { + let mut current = &mut self.evaluation; + loop { + match current.steps.last_mut() { + Some(WipProbeStep::NestedProbe(p)) => current = p, + Some(WipProbeStep::EvaluateGoals(evaluation)) => return evaluation, + _ => bug!(), + } + } + } + fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { let evaluation = self.evaluation.finalize(); match evaluation.kind { @@ -202,8 +220,10 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { #[derive(Eq, PartialEq, Debug)] struct WipProbe<'tcx> { - pub steps: Vec>, - pub kind: Option>, + initial_num_var_values: usize, + steps: Vec>, + kind: Option>, + final_state: Option>, } impl<'tcx> WipProbe<'tcx> { @@ -211,6 +231,7 @@ impl<'tcx> WipProbe<'tcx> { inspect::Probe { steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(), kind: self.kind.unwrap(), + final_state: self.final_state.unwrap(), } } } @@ -220,6 +241,7 @@ enum WipProbeStep<'tcx> { AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>), EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), NestedProbe(WipProbe<'tcx>), + MakeCanonicalResponse { shallow_certainty: Certainty }, } impl<'tcx> WipProbeStep<'tcx> { @@ -228,6 +250,9 @@ impl<'tcx> WipProbeStep<'tcx> { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), + WipProbeStep::MakeCanonicalResponse { shallow_certainty } => { + inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } + } } } } @@ -245,6 +270,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> { self.state.as_deref_mut() } + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<'tcx> { + let mut nested = ProofTreeBuilder { state: self.state.take() }; + nested.enter_probe(); + nested + } + pub fn finalize(self) -> Option> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { @@ -362,11 +393,14 @@ impl<'tcx> ProofTreeBuilder<'tcx> { if let Some(this) = self.as_mut() { match (this, *goal_evaluation.state.unwrap()) { ( - DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { - evaluations, .. - }), + DebugSolver::GoalEvaluationStep(state), DebugSolver::GoalEvaluation(goal_evaluation), - ) => evaluations.last_mut().unwrap().push(goal_evaluation), + ) => state + .added_goals_evaluation() + .evaluations + .last_mut() + .unwrap() + .push(goal_evaluation), (this @ DebugSolver::Root, goal_evaluation) => *this = goal_evaluation, _ => unreachable!(), } @@ -375,13 +409,22 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn new_goal_evaluation_step( &mut self, + var_values: CanonicalVarValues<'tcx>, instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, ) -> ProofTreeBuilder<'tcx> { self.nested(|| WipGoalEvaluationStep { + var_values: var_values.var_values.to_vec(), instantiated_goal, - evaluation: WipProbe { steps: vec![], kind: None }, + evaluation: WipProbe { + initial_num_var_values: var_values.len(), + steps: vec![], + kind: None, + final_state: None, + }, + probe_depth: 0, }) } + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { @@ -396,112 +439,159 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn new_probe(&mut self) -> ProofTreeBuilder<'tcx> { - self.nested(|| WipProbe { steps: vec![], kind: None }) + pub fn add_var_value>>(&mut self, arg: T) { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + state.var_values.push(arg.into()); + } + Some(s) => bug!("tried to add var values to {s:?}"), + } + } + + pub fn enter_probe(&mut self) { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + let initial_num_var_values = state.var_values.len(); + state.current_evaluation_scope().steps.push(WipProbeStep::NestedProbe(WipProbe { + initial_num_var_values, + steps: vec![], + kind: None, + final_state: None, + })); + state.probe_depth += 1; + } + Some(s) => bug!("tried to start probe to {s:?}"), + } } pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<'tcx>) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::Probe(this) => { - assert_eq!(this.kind.replace(probe_kind), None) - } - _ => unreachable!(), + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + let prev = state.current_evaluation_scope().kind.replace(probe_kind); + assert_eq!(prev, None); } + _ => bug!(), } } - pub fn add_normalizes_to_goal( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + pub fn probe_final_state( + &mut self, + infcx: &InferCtxt<'tcx>, + max_input_universe: ty::UniverseIndex, ) { - if ecx.inspect.is_noop() { - return; + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + let final_state = canonical::make_canonical_state( + infcx, + &state.var_values, + max_input_universe, + (), + ); + let prev = state.current_evaluation_scope().final_state.replace(final_state); + assert_eq!(prev, None); + } + _ => bug!(), } + } - Self::add_goal(ecx, GoalSource::Misc, goal.with(ecx.tcx(), goal.predicate)); + pub fn add_normalizes_to_goal( + &mut self, + infcx: &InferCtxt<'tcx>, + max_input_universe: ty::UniverseIndex, + goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + ) { + self.add_goal( + infcx, + max_input_universe, + GoalSource::Misc, + goal.with(infcx.tcx, goal.predicate), + ); } pub fn add_goal( - ecx: &mut EvalCtxt<'_, 'tcx>, + &mut self, + infcx: &InferCtxt<'tcx>, + max_input_universe: ty::UniverseIndex, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) { - // Can't use `if let Some(this) = ecx.inspect.as_mut()` here because - // we have to immutably use the `EvalCtxt` for `make_canonical_state`. - if ecx.inspect.is_noop() { - return; + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + let goal = canonical::make_canonical_state( + infcx, + &state.var_values, + max_input_universe, + goal, + ); + state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) + } + _ => bug!(), } + } - let goal = Self::make_canonical_state(ecx, goal); - - match ecx.inspect.as_mut().unwrap() { - DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipProbe { steps, .. }, - .. - }) - | DebugSolver::Probe(WipProbe { steps, .. }) => { - steps.push(WipProbeStep::AddGoal(source, goal)) + pub fn make_canonical_response(&mut self, shallow_certainty: Certainty) { + match self.as_mut() { + Some(DebugSolver::GoalEvaluationStep(state)) => { + state + .current_evaluation_scope() + .steps + .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } - s => unreachable!("tried to add {goal:?} to {s:?}"), + None => {} + _ => {} } } - pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) { - if let Some(this) = self.as_mut() { - match (this, *probe.state.unwrap()) { - ( - DebugSolver::Probe(WipProbe { steps, .. }) - | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipProbe { steps, .. }, - .. - }), - DebugSolver::Probe(probe), - ) => steps.push(WipProbeStep::NestedProbe(probe)), - _ => unreachable!(), + pub fn finish_probe(mut self) -> ProofTreeBuilder<'tcx> { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + assert_ne!(state.probe_depth, 0); + let num_var_values = state.current_evaluation_scope().initial_num_var_values; + state.var_values.truncate(num_var_values); + state.probe_depth -= 1; } + _ => bug!(), } - } - pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { - self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None }) + self } - pub fn evaluate_added_goals_loop_start(&mut self) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::AddedGoalsEvaluation(this) => { - this.evaluations.push(vec![]); - } - _ => unreachable!(), + pub fn start_evaluate_added_goals(&mut self) { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + state.current_evaluation_scope().steps.push(WipProbeStep::EvaluateGoals( + WipAddedGoalsEvaluation { evaluations: vec![], result: None }, + )); } + _ => bug!(), } } - pub fn eval_added_goals_result(&mut self, result: Result) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::AddedGoalsEvaluation(this) => { - assert_eq!(this.result.replace(result), None); - } - _ => unreachable!(), + pub fn start_evaluate_added_goals_step(&mut self) { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + state.added_goals_evaluation().evaluations.push(vec![]); } + _ => bug!(), } } - pub fn added_goals_evaluation(&mut self, added_goals_evaluation: ProofTreeBuilder<'tcx>) { - if let Some(this) = self.as_mut() { - match (this, *added_goals_evaluation.state.unwrap()) { - ( - DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipProbe { steps, .. }, - .. - }) - | DebugSolver::Probe(WipProbe { steps, .. }), - DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), - ) => steps.push(WipProbeStep::EvaluateGoals(added_goals_evaluation)), - _ => unreachable!(), + pub fn evaluate_added_goals_result(&mut self, result: Result) { + match self.as_mut() { + None => {} + Some(DebugSolver::GoalEvaluationStep(state)) => { + let prev = state.added_goals_evaluation().result.replace(result); + assert_eq!(prev, None); } + _ => bug!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index da5cd15a10d71..b2b076e28e648 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; +use rustc_macros::extension; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response, @@ -200,18 +201,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self))] - fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { - inspect::ProofTreeBuilder::add_normalizes_to_goal(self, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - - #[instrument(level = "debug", skip(self))] - fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) { - inspect::ProofTreeBuilder::add_goal(self, source, goal); - self.nested_goals.goals.push((source, goal)); - } - #[instrument(level = "debug", skip(self, goals))] fn add_goals( &mut self, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index ebf2a0d96213f..dab87fffe461e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -8,11 +8,10 @@ use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::inspect::ProbeKind; +use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; -use rustc_middle::traits::solve::{ - CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult, -}; +use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::NormalizesTo; @@ -119,14 +118,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, + source: CandidateSource, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let tcx = ecx.tcx(); - ecx.probe_misc_candidate("assumption").enter(|ecx| { + ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); ecx.eq( @@ -300,14 +300,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_error_guaranteed_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, _guar: ErrorGuaranteed, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { ecx.tcx().dcx().span_delayed_bug( ecx.tcx().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", @@ -318,35 +318,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_trait_alias_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`FnPtr` does not have an associated type: {:?}", goal); } @@ -354,7 +354,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = ecx.tcx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -364,8 +364,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { )? { Some(tupled_inputs_and_output) => tupled_inputs_and_output, None => { - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { @@ -385,14 +384,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) + Self::probe_and_consider_implied_clause( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + pred, + [goal.with(tcx, output_is_sized_pred)], + ) } fn consider_builtin_async_fn_trait_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = ecx.tcx(); let env_region = match goal_kind { @@ -461,8 +466,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, [goal.with(tcx, output_is_sized_pred)] @@ -474,7 +480,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let [ closure_fn_kind_ty, goal_kind_ty, @@ -489,7 +495,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // Bail if the upvars haven't been constrained. if tupled_upvars_ty.expect_ty().is_ty_var() { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + return ecx.forced_ambiguity(MaybeCause::Ambiguity); } let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { @@ -512,25 +518,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { borrow_region.expect_region(), ); - ecx.instantiate_normalizes_to_term(goal, upvars_ty.into()); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, upvars_ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_tuple_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = ecx.tcx(); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, goal.predicate.def_id()); - ecx.probe_misc_candidate("builtin pointee").enter(|ecx| { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { ty::Bool | ty::Char @@ -609,7 +617,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -623,8 +631,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let term = args.as_coroutine().return_ty().into(); - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), @@ -640,7 +649,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -654,8 +663,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let term = args.as_coroutine().yield_ty().into(); - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), @@ -671,14 +681,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_fused_iterator_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -690,7 +700,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { return Err(NoSolution); } - ecx.probe_misc_candidate("builtin AsyncIterator kind").enter(|ecx| { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let expected_ty = ecx.next_ty_infer(); // Take `AsyncIterator` and turn it into the corresponding // coroutine yield ty `Poll>`. @@ -714,7 +724,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -737,8 +747,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`") }; - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { projection_ty: ty::AliasTy::new( @@ -758,14 +769,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { + ) -> Vec> { bug!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); let discriminant_ty = match *self_ty.kind() { ty::Bool @@ -808,23 +819,76 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), }; - ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.instantiate_normalizes_to_term(goal, discriminant_ty.into()); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + fn consider_builtin_async_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> Result, NoSolution> { + let self_ty = goal.predicate.self_ty(); + let async_destructor_ty = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Never + | ty::Adt(_, _) + | ty::Str + | ty::Slice(_) + | ty::Tuple(_) + | ty::Error(_) => self_ty.async_destructor_ty(ecx.tcx(), goal.param_env), + + // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder + // types, which return `::AsyncDestructor` + // (or ICE in the case of placeholders). Projecting a type to itself + // is never really productive. + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { + return Err(NoSolution); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Foreign(..) + | ty::Bound(..) => bug!( + "unexpected self ty `{:?}` when normalizing `::AsyncDestructor`", + goal.predicate.self_ty() + ), + + ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => bug!( + "`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}" + ), + }; + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.eq(goal.param_env, goal.predicate.term, async_destructor_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + fn consider_builtin_destruct_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e522339358ade..c8cb14abb554d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -9,12 +9,11 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::MaybeCause; use rustc_middle::traits::solve::inspect::ProbeKind; -use rustc_middle::traits::solve::{ - CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult, -}; +use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; use rustc_middle::traits::{BuiltinImplSource, Reveal}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; @@ -94,21 +93,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, _guar: ErrorGuaranteed, - ) -> QueryResult<'tcx> { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ) -> Result, NoSolution> { + // FIXME: don't need to enter a probe here. + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, + source: CandidateSource, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity { - ecx.probe_misc_candidate("assumption").enter(|ecx| { + ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); ecx.eq( goal.param_env, @@ -128,7 +130,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -162,6 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } ecx.probe_and_evaluate_goal_for_constituent_tys( + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, structural_traits::instantiate_constituent_tys_for_auto_trait, ) @@ -170,14 +173,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } let tcx = ecx.tcx(); - ecx.probe_misc_candidate("trait alias").enter(|ecx| { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) .instantiate(tcx, goal.predicate.trait_ref.args); @@ -193,12 +196,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } ecx.probe_and_evaluate_goal_for_constituent_tys( + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, structural_traits::instantiate_constituent_tys_for_sized_trait, ) @@ -207,12 +211,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } ecx.probe_and_evaluate_goal_for_constituent_tys( + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, structural_traits::instantiate_constituent_tys_for_copy_clone_trait, ) @@ -221,7 +226,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -234,14 +239,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty())); // But if there are inference variables, we have to wait until it's resolved. if key.has_non_region_infer() { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + return ecx.forced_ambiguity(MaybeCause::Ambiguity); } if let Ok(layout) = tcx.layout_of(key) && layout.layout.is_pointer_like(&tcx.data_layout) { // FIXME: We could make this faster by making a no-constraints response - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { Err(NoSolution) } @@ -250,13 +256,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { // impl FnPtr for FnPtr {} ty::PredicatePolarity::Positive => { if self_ty.is_fn_ptr() { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } else { Err(NoSolution) } @@ -266,7 +274,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // If a type is rigid and not a fn ptr, then we know for certain // that it does *not* implement `FnPtr`. if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } else { Err(NoSolution) } @@ -278,7 +288,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -292,8 +302,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { )? { Some(a) => a, None => { - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { @@ -307,14 +316,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .to_predicate(tcx); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) + Self::probe_and_consider_implied_clause( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + pred, + [goal.with(tcx, output_is_sized_pred)], + ) } fn consider_builtin_async_fn_trait_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -345,8 +360,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .to_predicate(tcx); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, [goal.with(tcx, output_is_sized_pred)] @@ -358,7 +374,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { bug!(); }; @@ -369,7 +385,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(); if closure_kind.extends(goal_kind) { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { Err(NoSolution) } @@ -384,13 +401,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } if let ty::Tuple(..) = goal.predicate.self_ty().kind() { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { Err(NoSolution) } @@ -399,18 +417,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -428,13 +447,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Async coroutine unconditionally implement `Future` // Technically, we need to check that the future output type is Sized, // but that's already proven by the coroutine being WF. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // FIXME: use `consider_implied` + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -452,13 +473,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Gen coroutines unconditionally implement `Iterator` // Technically, we need to check that the iterator output type is Sized, // but that's already proven by the coroutines being WF. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // FIXME: use `consider_implied` + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -474,13 +497,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // Gen coroutines unconditionally implement `FusedIterator` - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // FIXME: use `consider_implied` + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -498,13 +523,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Gen coroutines unconditionally implement `Iterator` // Technically, we need to check that the iterator output type is Sized, // but that's already proven by the coroutines being WF. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // FIXME: use `consider_implied` + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -521,8 +548,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let coroutine = args.as_coroutine(); - Self::consider_implied_clause( + Self::probe_and_consider_implied_clause( ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()]) .to_predicate(tcx), @@ -535,19 +563,33 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } // `DiscriminantKind` is automatically implemented for every type. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } + + fn consider_builtin_async_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> Result, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + + // `AsyncDestruct` is automatically implemented for every type. + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -556,13 +598,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `Destruct` is automatically implemented for every type in // non-const environments. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -582,11 +625,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); }; - let certainty = ecx.is_transmutable( - rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) }, - assume, - )?; - ecx.evaluate_added_goals_and_make_canonical_response(certainty) + // FIXME: This actually should destructure the `Result` we get from transmutability and + // register candiates. We probably need to register >1 since we may have an OR of ANDs. + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let certainty = ecx.is_transmutable( + rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) }, + assume, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(certainty) + }) } /// ```ignore (builtin impl example) @@ -599,20 +646,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { + ) -> Vec> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return vec![]; } - let misc_candidate = |ecx: &mut EvalCtxt<'_, 'tcx>, certainty| { - ( - ecx.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(), - BuiltinImplSource::Misc, - ) - }; - - let result_to_single = |result, source| match result { - Ok(resp) => vec![(resp, source)], + let result_to_single = |result| match result { + Ok(resp) => vec![resp], Err(NoSolution) => vec![], }; @@ -630,7 +670,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"), - (_, ty::Infer(ty::TyVar(..))) => vec![misc_candidate(ecx, Certainty::AMBIGUOUS)], + + (_, ty::Infer(ty::TyVar(..))) => { + result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity)) + } // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`. ( @@ -643,14 +686,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `T` -> `dyn Trait` unsizing. (_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data), - BuiltinImplSource::Misc, ), // `[T; N]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single( - ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty), - BuiltinImplSource::Misc, - ), + (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty)) + } // `Struct` -> `Struct` where `T: Unsize` (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) @@ -658,7 +699,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { { result_to_single( ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args), - BuiltinImplSource::Misc, ) } @@ -666,10 +706,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() && !a_tys.is_empty() => { - result_to_single( - ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys), - BuiltinImplSource::TupleUnsizing, - ) + result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys)) } _ => vec![], @@ -695,7 +732,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { a_region: ty::Region<'tcx>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { + ) -> Vec> { let tcx = self.tcx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; @@ -703,35 +740,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // If the principal def ids match (or are both none), then we're not doing // trait upcasting. We're just removing auto traits (or shortening the lifetime). if a_data.principal_def_id() == b_data.principal_def_id() { - if let Ok(resp) = self.consider_builtin_upcast_to_principal( + responses.extend(self.consider_builtin_upcast_to_principal( goal, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), a_data, a_region, b_data, b_region, a_data.principal(), - ) { - responses.push((resp, BuiltinImplSource::Misc)); - } + )); } else if let Some(a_principal) = a_data.principal() { self.walk_vtable( a_principal.with_self_ty(tcx, a_ty), |ecx, new_a_principal, _, vtable_vptr_slot| { - if let Ok(resp) = ecx.probe_misc_candidate("dyn upcast").enter(|ecx| { - ecx.consider_builtin_upcast_to_principal( - goal, - a_data, - a_region, - b_data, - b_region, - Some(new_a_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - })), - ) - }) { - responses - .push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot })); - } + responses.extend(ecx.consider_builtin_upcast_to_principal( + goal, + CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting { + vtable_vptr_slot, + }), + a_data, + a_region, + b_data, + b_region, + Some(new_a_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + })), + )); }, ); } @@ -744,7 +778,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = self.tcx(); let Goal { predicate: (a_ty, _), .. } = goal; @@ -753,37 +787,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Err(NoSolution); } - // Check that the type implements all of the predicates of the trait object. - // (i.e. the principal, all of the associated types match, and any auto traits) - self.add_goals( - GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - - // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - self.add_goal( + self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + // Check that the type implements all of the predicates of the trait object. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals( GoalSource::ImplWhereBound, - goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), + b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), ); - } else { - return Err(NoSolution); - } - // The type must outlive the lifetime of the `dyn` we're unsizing into. - self.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // The type must be `Sized` to be unsized. + if let Some(sized_def_id) = tcx.lang_items().sized_trait() { + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), + ); + } else { + return Err(NoSolution); + } + + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_upcast_to_principal( &mut self, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, + source: CandidateSource, a_data: &'tcx ty::List>, a_region: ty::Region<'tcx>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, upcast_principal: Option>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let param_env = goal.param_env; // We may upcast to auto traits that are either explicitly listed in @@ -802,7 +839,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // having any inference side-effects. We process obligations because // unification may initially succeed due to deferred projection equality. let projection_may_match = - |ecx: &mut Self, + |ecx: &mut EvalCtxt<'_, 'tcx>, source_projection: ty::PolyExistentialProjection<'tcx>, target_projection: ty::PolyExistentialProjection<'tcx>| { source_projection.item_def_id() == target_projection.item_def_id() @@ -816,54 +853,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .is_ok() }; - for bound in b_data { - match bound.skip_binder() { - // Check that a's supertrait (upcast_principal) is compatible - // with the target (b_ty). - ty::ExistentialPredicate::Trait(target_principal) => { - self.eq(param_env, upcast_principal.unwrap(), bound.rebind(target_principal))?; - } - // Check that b_ty's projection is satisfied by exactly one of - // a_ty's projections. First, we look through the list to see if - // any match. If not, error. Then, if *more* than one matches, we - // return ambiguity. Otherwise, if exactly one matches, equate - // it with b_ty's projection. - ty::ExistentialPredicate::Projection(target_projection) => { - let target_projection = bound.rebind(target_projection); - let mut matching_projections = - a_data.projection_bounds().filter(|source_projection| { - projection_may_match(self, *source_projection, target_projection) - }); - let Some(source_projection) = matching_projections.next() else { - return Err(NoSolution); - }; - if matching_projections.next().is_some() { - return self.evaluate_added_goals_and_make_canonical_response( - Certainty::AMBIGUOUS, - ); + self.probe_trait_candidate(source).enter(|ecx| { + for bound in b_data { + match bound.skip_binder() { + // Check that a's supertrait (upcast_principal) is compatible + // with the target (b_ty). + ty::ExistentialPredicate::Trait(target_principal) => { + ecx.eq( + param_env, + upcast_principal.unwrap(), + bound.rebind(target_principal), + )?; } - self.eq(param_env, source_projection, target_projection)?; - } - // Check that b_ty's auto traits are present in a_ty's bounds. - ty::ExistentialPredicate::AutoTrait(def_id) => { - if !a_auto_traits.contains(&def_id) { - return Err(NoSolution); + // Check that b_ty's projection is satisfied by exactly one of + // a_ty's projections. First, we look through the list to see if + // any match. If not, error. Then, if *more* than one matches, we + // return ambiguity. Otherwise, if exactly one matches, equate + // it with b_ty's projection. + ty::ExistentialPredicate::Projection(target_projection) => { + let target_projection = bound.rebind(target_projection); + let mut matching_projections = + a_data.projection_bounds().filter(|source_projection| { + projection_may_match(ecx, *source_projection, target_projection) + }); + let Some(source_projection) = matching_projections.next() else { + return Err(NoSolution); + }; + if matching_projections.next().is_some() { + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + ecx.eq(param_env, source_projection, target_projection)?; + } + // Check that b_ty's auto traits are present in a_ty's bounds. + ty::ExistentialPredicate::AutoTrait(def_id) => { + if !a_auto_traits.contains(&def_id) { + return Err(NoSolution); + } } } } - } - // Also require that a_ty's lifetime outlives b_ty's lifetime. - self.add_goal( - GoalSource::ImplWhereBound, - Goal::new( - self.tcx(), - param_env, - ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), - ), - ); + // Also require that a_ty's lifetime outlives b_ty's lifetime. + ecx.add_goal( + GoalSource::ImplWhereBound, + Goal::new( + ecx.tcx(), + param_env, + ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), + ), + ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } /// We have the following builtin impls for arrays: @@ -879,9 +922,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_elem_ty: Ty<'tcx>, b_elem_ty: Ty<'tcx>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } /// We generate a builtin `Unsize` impls for structs with generic parameters only @@ -903,7 +947,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { def: ty::AdtDef<'tcx>, a_args: ty::GenericArgsRef<'tcx>, b_args: ty::GenericArgsRef<'tcx>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = self.tcx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -945,7 +989,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ), ), ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } /// We generate the following builtin impl for tuples of all sizes. @@ -963,7 +1008,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_tys: &'tcx ty::List>, b_tys: &'tcx ty::List>, - ) -> QueryResult<'tcx> { + ) -> Result, NoSolution> { let tcx = self.tcx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -987,7 +1032,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ), ), ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } // Return `Some` if there is an impl (built-in or user provided) that may @@ -997,7 +1043,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn disqualify_auto_trait_candidate_due_to_possible_impl( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> Option> { + ) -> Option, NoSolution>> { let self_ty = goal.predicate.self_ty(); match *self_ty.kind() { // Stall int and float vars until they are resolved to a concrete @@ -1006,7 +1052,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // we probably don't want to treat an `impl !AutoTrait for i32` as // disqualifying the built-in auto impl for `i64: AutoTrait` either. ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)) + Some(self.forced_ambiguity(MaybeCause::Ambiguity)) } // These types cannot be structurally decomposed into constituent @@ -1027,12 +1073,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { { match self.tcx().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), - Movability::Movable => { - Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } + Movability::Movable => Some( + self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ), } } + // If we still have an alias here, it must be rigid. For opaques, it's always + // okay to consider auto traits because that'll reveal its hidden type. For + // non-opaque aliases, we will not assemble any candidates since there's no way + // to further look into its type. + ty::Alias(..) => None, + // For rigid types, any possible implementation that could apply to // the type (even if after unification and processing nested goals // it does not hold) will disqualify the built-in auto impl. @@ -1060,15 +1114,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::Adt(_, _) - // FIXME: Handling opaques here is kinda sus. Especially because we - // simplify them to SimplifiedType::Placeholder. - | ty::Alias(ty::Opaque, _) => { + | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.tcx().for_each_relevant_impl_treating_projections( + self.tcx().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, |impl_def_id| { disqualifying_impl = Some(impl_def_id); }, @@ -1092,13 +1142,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// wrapped in one. fn probe_and_evaluate_goal_for_constituent_tys( &mut self, + source: CandidateSource, goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn( &EvalCtxt<'_, 'tcx>, Ty<'tcx>, ) -> Result>>, NoSolution>, - ) -> QueryResult<'tcx> { - self.probe_misc_candidate("constituent tys").enter(|ecx| { + ) -> Result, NoSolution> { + self.probe_trait_candidate(source).enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, constituent_tys(ecx, goal.predicate.self_ty())? diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f9e7ed9dcbbd6..053de2c673b8a 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -784,7 +784,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2) + match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::Yes,c1, c2) { Ok(_) => (), Err(_) => return false, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 36028b516591b..86e7c42376aa0 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -20,30 +20,44 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::DefId; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use std::fmt::Debug; use std::ops::ControlFlow; use super::error_reporting::suggest_new_overflow_limit; -/// Whether we do the orphan check relative to this crate or -/// to some remote crate. +/// Whether we do the orphan check relative to this crate or to some remote crate. #[derive(Copy, Clone, Debug)] -enum InCrate { - Local, +pub enum InCrate { + Local { mode: OrphanCheckMode }, Remote, } +#[derive(Copy, Clone, Debug)] +pub enum OrphanCheckMode { + /// Proper orphan check. + Proper, + /// Improper orphan check for backward compatibility. + /// + /// In this mode, type params inside projections are considered to be covered + /// even if the projection may normalize to a type that doesn't actually cover + /// them. This is unsound. See also [#124559] and [#99554]. + /// + /// [#124559]: https://github.com/rust-lang/rust/issues/124559 + /// [#99554]: https://github.com/rust-lang/rust/issues/99554 + Compat, +} + #[derive(Debug, Copy, Clone)] pub enum Conflict { Upstream, @@ -604,19 +618,20 @@ fn try_prove_negated_where_clause<'tcx>( /// This both checks whether any downstream or sibling crates could /// implement it and whether an upstream crate can add this impl /// without breaking backwards compatibility. -#[instrument(level = "debug", skip(tcx, lazily_normalize_ty), ret)] +#[instrument(level = "debug", skip(infcx, lazily_normalize_ty), ret)] pub fn trait_ref_is_knowable<'tcx, E: Debug>( - tcx: TyCtxt<'tcx>, + infcx: &InferCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result, E>, ) -> Result, E> { - if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() { + if orphan_check_trait_ref(infcx, trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() + { // A downstream or cousin crate is allowed to implement some // generic parameters of this trait-ref. return Ok(Err(Conflict::Downstream)); } - if trait_ref_is_local_or_fundamental(tcx, trait_ref) { + if trait_ref_is_local_or_fundamental(infcx.tcx, trait_ref) { // This is a local or fundamental trait, so future-compatibility // is no concern. We know that downstream/cousin crates are not // allowed to implement a generic parameter of this trait ref, @@ -633,7 +648,14 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>( // and if we are an intermediate owner, then we don't care // about future-compatibility, which means that we're OK if // we are an owner. - if orphan_check_trait_ref(trait_ref, InCrate::Local, &mut lazily_normalize_ty)?.is_ok() { + if orphan_check_trait_ref( + infcx, + trait_ref, + InCrate::Local { mode: OrphanCheckMode::Proper }, + &mut lazily_normalize_ty, + )? + .is_ok() + { Ok(Ok(())) } else { Ok(Err(Conflict::Upstream)) @@ -644,7 +666,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, ) -> bool { - trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) + trait_ref.def_id.is_local() || tcx.has_attr(trait_ref.def_id, sym::fundamental) } #[derive(Debug, Copy, Clone)] @@ -663,31 +685,15 @@ impl From for IsFirstInputType { } #[derive(Debug)] -pub enum OrphanCheckErr<'tcx> { +pub enum OrphanCheckErr<'tcx, T> { NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>), - UncoveredTy(Ty<'tcx>, Option>), + UncoveredTyParams(UncoveredTyParams<'tcx, T>), } -/// Checks the coherence orphan rules. `impl_def_id` should be the -/// `DefId` of a trait impl. To pass, either the trait must be local, or else -/// two conditions must be satisfied: -/// -/// 1. All type parameters in `Self` must be "covered" by some local type constructor. -/// 2. Some local type must appear in `Self`. -#[instrument(level = "debug", skip(tcx), ret)] -pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { - // We only except this routine to be invoked on implementations - // of a trait, not inherent implementations. - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); - debug!(?trait_ref); - - // If the *trait* is local to the crate, ok. - if trait_ref.def_id.is_local() { - debug!("trait {:?} is local to current crate", trait_ref.def_id); - return Ok(()); - } - - orphan_check_trait_ref::(trait_ref, InCrate::Local, |ty| Ok(ty)).unwrap() +#[derive(Debug)] +pub struct UncoveredTyParams<'tcx, T> { + pub uncovered: T, + pub local_ty: Option>, } /// Checks whether a trait-ref is potentially implementable by a crate. @@ -735,6 +741,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// To check that a local impl follows the orphan rules, we check it in /// InCrate::Local mode, using type parameters for the "generic" types. /// +/// In InCrate::Local mode the orphan check succeeds if the current crate +/// is definitely allowed to implement the given trait (no false positives). +/// /// 2. They ground negative reasoning for coherence. If a user wants to /// write both a conditional blanket impl and a specific impl, we need to /// make sure they do not overlap. For example, if we write @@ -753,6 +762,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// try to implement this trait-ref. To check for this, we use InCrate::Remote /// mode. That is sound because we already know all the impls from known crates. /// +/// In InCrate::Remote mode the orphan check succeeds if a foreign crate +/// *could* implement the given trait (no false negatives). +/// /// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can /// add "non-blanket" impls without breaking negative reasoning in dependent /// crates. This is the "rebalancing coherence" (RFC 1023) restriction. @@ -776,54 +788,56 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// /// Note that this function is never called for types that have both type /// parameters and inference variables. -#[instrument(level = "trace", skip(lazily_normalize_ty), ret)] -fn orphan_check_trait_ref<'tcx, E: Debug>( +#[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)] +pub fn orphan_check_trait_ref<'tcx, E: Debug>( + infcx: &InferCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, in_crate: InCrate, lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result, E>, -) -> Result>, E> { - if trait_ref.has_infer() && trait_ref.has_param() { - bug!( - "can't orphan check a trait ref with both params and inference variables {:?}", - trait_ref - ); +) -> Result>>, E> { + if trait_ref.has_param() { + bug!("orphan check only expects inference variables: {trait_ref:?}"); } - let mut checker = OrphanChecker::new(in_crate, lazily_normalize_ty); + let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty); Ok(match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), - ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)) => return Err(err), - ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { - // Does there exist some local type after the `ParamTy`. - checker.search_first_local_ty = true; - if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) = - trait_ref.visit_with(&mut checker).break_value() - { - Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty))) - } else { - Err(OrphanCheckErr::UncoveredTy(ty, None)) + ControlFlow::Break(residual) => match residual { + OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err), + OrphanCheckEarlyExit::UncoveredTyParam(ty) => { + // Does there exist some local type after the `ParamTy`. + checker.search_first_local_ty = true; + let local_ty = match trait_ref.visit_with(&mut checker).break_value() { + Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty), + _ => None, + }; + Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { + uncovered: ty, + local_ty, + })) } - } - ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()), + OrphanCheckEarlyExit::LocalTy(_) => Ok(()), + }, }) } -struct OrphanChecker<'tcx, F> { +struct OrphanChecker<'a, 'tcx, F> { + infcx: &'a InferCtxt<'tcx>, in_crate: InCrate, in_self_ty: bool, lazily_normalize_ty: F, - /// Ignore orphan check failures and exclusively search for the first - /// local type. + /// Ignore orphan check failures and exclusively search for the first local type. search_first_local_ty: bool, non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>, } -impl<'tcx, F, E> OrphanChecker<'tcx, F> +impl<'a, 'tcx, F, E> OrphanChecker<'a, 'tcx, F> where F: FnOnce(Ty<'tcx>) -> Result, E>, { - fn new(in_crate: InCrate, lazily_normalize_ty: F) -> Self { + fn new(infcx: &'a InferCtxt<'tcx>, in_crate: InCrate, lazily_normalize_ty: F) -> Self { OrphanChecker { + infcx, in_crate, in_self_ty: true, lazily_normalize_ty, @@ -837,17 +851,20 @@ where ControlFlow::Continue(()) } - fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { + fn found_uncovered_ty_param( + &mut self, + ty: Ty<'tcx>, + ) -> ControlFlow> { if self.search_first_local_ty { - ControlFlow::Continue(()) - } else { - ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) + return ControlFlow::Continue(()); } + + ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty)) } fn def_id_is_local(&mut self, def_id: DefId) -> bool { match self.in_crate { - InCrate::Local => def_id.is_local(), + InCrate::Local { .. } => def_id.is_local(), InCrate::Remote => false, } } @@ -855,23 +872,25 @@ where enum OrphanCheckEarlyExit<'tcx, E> { NormalizationFailure(E), - ParamTy(Ty<'tcx>), + UncoveredTyParam(Ty<'tcx>), LocalTy(Ty<'tcx>), } -impl<'tcx, F, E> TypeVisitor> for OrphanChecker<'tcx, F> +impl<'a, 'tcx, F, E> TypeVisitor> for OrphanChecker<'a, 'tcx, F> where F: FnMut(Ty<'tcx>) -> Result, E>, { type Result = ControlFlow>; + fn visit_region(&mut self, _r: ty::Region<'tcx>) -> Self::Result { ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - // Need to lazily normalize here in with `-Znext-solver=coherence`. + let ty = self.infcx.shallow_resolve(ty); let ty = match (self.lazily_normalize_ty)(ty) { - Ok(ty) => ty, + Ok(norm_ty) if norm_ty.is_ty_var() => ty, + Ok(norm_ty) => norm_ty, Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)), }; @@ -889,19 +908,46 @@ where | ty::Slice(..) | ty::RawPtr(..) | ty::Never - | ty::Tuple(..) - | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => { - self.found_non_local_ty(ty) + | ty::Tuple(..) => self.found_non_local_ty(ty), + + ty::Param(..) => bug!("unexpected ty param"), + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => { + match self.in_crate { + InCrate::Local { .. } => self.found_uncovered_ty_param(ty), + // The inference variable might be unified with a local + // type in that remote crate. + InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + } } - ty::Param(..) => self.found_param_ty(ty), + ty::Alias(kind @ (ty::Projection | ty::Inherent | ty::Weak), ..) => { + if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) { + bug!("unexpected ty param in alias ty"); + } - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate { - InCrate::Local => self.found_non_local_ty(ty), - // The inference variable might be unified with a local - // type in that remote crate. - InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - }, + if ty.has_type_flags( + ty::TypeFlags::HAS_TY_PLACEHOLDER + | ty::TypeFlags::HAS_TY_BOUND + | ty::TypeFlags::HAS_TY_INFER, + ) { + match self.in_crate { + InCrate::Local { mode } => match kind { + ty::Projection if let OrphanCheckMode::Compat = mode => { + ControlFlow::Continue(()) + } + _ => self.found_uncovered_ty_param(ty), + }, + InCrate::Remote => { + // The inference variable might be unified with a local + // type in that remote crate. + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } + } + } else { + ControlFlow::Continue(()) + } + } // For fundamental types, we just look inside of them. ty::Ref(_, ty, _) => ty.visit_with(self), @@ -1022,10 +1068,14 @@ struct AmbiguityCausesVisitor<'a, 'tcx> { } impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { + fn span(&self) -> Span { + DUMMY_SP + } + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) { let infcx = goal.infcx(); for cand in goal.candidates() { - cand.visit_nested(self); + cand.visit_nested_in_probe(self); } // When searching for intercrate ambiguity causes, we only need to look // at ambiguous goals, as for others the coherence unknowable candidate @@ -1074,9 +1124,8 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { // Add ambiguity causes for unknowable goals. let mut ambiguity_cause = None; for cand in goal.candidates() { - // FIXME: boiiii, using string comparisions here sure is scuffed. - if let inspect::ProbeKind::MiscCandidate { - name: "coherence unknowable", + if let inspect::ProbeKind::TraitCandidate { + source: CandidateSource::CoherenceUnknowable, result: Ok(_), } = cand.kind() { @@ -1099,7 +1148,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { }; infcx.probe(|_| { - match trait_ref_is_knowable(infcx.tcx, trait_ref, lazily_normalize_ty) { + match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) { Err(()) => {} Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Err(conflict)) => { @@ -1157,5 +1206,5 @@ fn search_ambiguity_causes<'tcx>( goal: Goal<'tcx, ty::Predicate<'tcx>>, causes: &mut FxIndexSet>, ) { - infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes }); + infcx.probe(|_| infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes })); } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 9fbec174ce8d2..432d51ff8f90b 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -19,6 +19,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::traits::{ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, }; +use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index d41d43bad7181..9e5701ffffc60 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -4,6 +4,7 @@ use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag}; use rustc_hir as hir; use rustc_hir::Node; +use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 837b784f2725a..e50edfdc656ce 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -50,22 +50,38 @@ pub struct FindExprBySpan<'hir> { pub span: Span, pub result: Option<&'hir hir::Expr<'hir>>, pub ty_result: Option<&'hir hir::Ty<'hir>>, + pub include_closures: bool, + pub tcx: TyCtxt<'hir>, } impl<'hir> FindExprBySpan<'hir> { - pub fn new(span: Span) -> Self { - Self { span, result: None, ty_result: None } + pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self { + Self { span, result: None, ty_result: None, tcx, include_closures: false } } } impl<'v> Visitor<'v> for FindExprBySpan<'v> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { if self.span == ex.span { self.result = Some(ex); } else { + if let hir::ExprKind::Closure(..) = ex.kind + && self.include_closures + && let closure_header_sp = self.span.with_hi(ex.span.hi()) + && closure_header_sp == ex.span + { + self.result = Some(ex); + } hir::intravisit::walk_expr(self, ex); } } + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { if self.span == ty.span { self.ty_result = Some(ty); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 5fccc76978550..07bd209e62394 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_macros::{extension, LintDiagnostic}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; @@ -128,7 +129,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) | ObligationCauseCode::ImplDerivedObligation(..) - | ObligationCauseCode::DerivedObligation(..) => {} + | ObligationCauseCode::WellFormedDerivedObligation(..) => {} _ => { // this is a "direct", user-specified, rather than derived, // obligation. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index db3794c1c40b7..3d2574ac92b66 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -26,6 +26,7 @@ use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; +use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError::{self, Sorts}; @@ -124,7 +125,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( msg: &str, err: &mut Diag<'_, G>, fn_sig: Option<&hir::FnSig<'_>>, - projection: Option<&ty::AliasTy<'_>>, + projection: Option>, trait_pred: ty::PolyTraitPredicate<'tcx>, // When we are dealing with a trait, `super_traits` will be `Some`: // Given `trait T: A + B + C {}` @@ -142,7 +143,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( let generics = tcx.generics_of(item_id); // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((param, bound_str, fn_sig)) = - fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() { + fn_sig.zip(projection).and_then(|(sig, p)| match *p.self_ty().kind() { // Shenanigans to get the `Trait` from the `impl Trait`. ty::Param(param) => { let param_def = generics.type_param(param, tcx); @@ -252,7 +253,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); let self_ty = trait_pred.skip_binder().self_ty(); - let (param_ty, projection) = match self_ty.kind() { + let (param_ty, projection) = match *self_ty.kind() { ty::Param(_) => (true, None), ty::Alias(ty::Projection, projection) => (false, Some(projection)), _ => (false, None), @@ -901,7 +902,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Remove all the desugaring and macro contexts. span.remove_mark(); } - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; @@ -1367,7 +1368,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return false; }; let body = self.tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(body.value); let Some(expr) = expr_finder.result else { return false; @@ -1469,7 +1470,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Remove all the hir desugaring contexts while maintaining the macro contexts. span.remove_mark(); } - let mut expr_finder = super::FindExprBySpan::new(span); + let mut expr_finder = super::FindExprBySpan::new(span, self.tcx); let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; @@ -2294,7 +2295,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { next_code = Some(&cause.derived.parent_code); } - ObligationCauseCode::DerivedObligation(derived_obligation) + ObligationCauseCode::WellFormedDerivedObligation(derived_obligation) | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); debug!( @@ -3423,7 +3424,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) }); } - ObligationCauseCode::DerivedObligation(ref data) => { + ObligationCauseCode::WellFormedDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_predicate = parent_trait_ref; // #74711: avoid a stack overflow diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 96596de32aa37..e50cb2af4b857 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -32,6 +32,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; +use rustc_macros::extension; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -780,7 +781,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && self.fallback_has_occurred { let predicate = trait_predicate.map_bound(|trait_pred| { - trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx)) + trait_pred.with_self_ty(self.tcx, tcx.types.unit) }); let unit_obligation = obligation.with(tcx, predicate); if self.predicate_may_hold(&unit_obligation) { @@ -2457,7 +2458,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(self.tcx.hir().body(body_id).value); if let Some(hir::Expr { @@ -2938,17 +2939,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } _ => {} }; + // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. - let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id) - { - (s, " +") + let (span, separator, open_paren_sp) = + if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { + (s, " +", open_paren_sp) + } else { + (param.name.ident().span.shrink_to_hi(), ":", None) + }; + + let mut suggs = vec![]; + let suggestion = format!("{separator} ?Sized"); + + if let Some(open_paren_sp) = open_paren_sp { + suggs.push((open_paren_sp, "(".to_string())); + suggs.push((span, format!("){suggestion}"))); } else { - (param.name.ident().span.shrink_to_hi(), ":") - }; - err.span_suggestion_verbose( - span, + suggs.push((span, suggestion)); + } + + err.multipart_suggestion_verbose( "consider relaxing the implicit `Sized` restriction", - format!("{separator} ?Sized"), + suggs, Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 8cd9f39d5d838..1f10cb715430d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -73,7 +73,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -static_assert_size!(PendingPredicateObligation<'_>, 72); +rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72); impl<'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8f5a30c436d33..56f8b4b9cdb82 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -41,8 +41,9 @@ use rustc_span::Span; use std::fmt::Debug; use std::ops::ControlFlow; -pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; -pub use self::coherence::{IsFirstInputType, OrphanCheckErr, OverlapResult}; +pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapping_impls}; +pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams}; +pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; @@ -482,7 +483,7 @@ fn is_impossible_associated_item( type Result = ControlFlow<()>; fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { // If this is a parameter from the trait item's own generics, then bail - if let ty::Param(param) = t.kind() + if let ty::Param(param) = *t.kind() && let param_def_id = self.generics.type_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { @@ -492,7 +493,7 @@ fn is_impossible_associated_item( } fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { if let ty::ReEarlyParam(param) = r.kind() - && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id + && let param_def_id = self.generics.region_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { return ControlFlow::Break(()); @@ -501,7 +502,7 @@ fn is_impossible_associated_item( } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { if let ty::ConstKind::Param(param) = ct.kind() - && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id + && let param_def_id = self.generics.const_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { return ControlFlow::Break(()); diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index b4969926f6423..43f4fa8e81ca1 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -8,6 +8,7 @@ use rustc_infer::infer::at::At; use rustc_infer::infer::InferOk; use rustc_infer::traits::PredicateObligation; use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; +use rustc_macros::extension; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder}; use rustc_middle::ty::{TypeFoldable, TypeSuperFoldable, TypeVisitable, TypeVisitableExt}; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5e1343b50ce7f..0e15dd275371b 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -519,7 +519,7 @@ fn virtual_call_violations_for_method<'tcx>( // e.g., `Rc<()>` let unit_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, Ty::new_unit(tcx), method.def_id); + receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method.def_id); match abi_of_ty(unit_receiver_ty) { Some(Abi::Scalar(..)) => (), diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index c4110df45dbb4..1dd2ada3356f7 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -3,6 +3,7 @@ use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::InferOk; +use rustc_macros::extension; use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints}; use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ca0b50864a81a..116e17c7e432f 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1074,6 +1074,42 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(..) | ty::Error(_) => false, } + } else if lang_items.async_destruct_trait() == Some(trait_ref.def_id) { + match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Pat(..) + | ty::Never + | ty::Tuple(..) + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + + // type parameters, opaques, and unnormalized projections don't have + // a known async destructor and may need to be normalized further or rely + // on param env for async destructor projections + ty::Param(_) + | ty::Foreign(_) + | ty::Alias(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Error(_) => false, + } } else if lang_items.pointee_trait() == Some(trait_ref.def_id) { let tail = selcx.tcx().struct_tail_with_normalize( self_ty, @@ -1488,15 +1524,20 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); - let args = tcx.mk_args(&[self_ty.into()]); let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); + let args = tcx.mk_args(&[self_ty.into()]); let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), Vec::new()) + } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0]; + assert_eq!(destructor_def_id, item_def_id); + + (self_ty.async_destructor_ty(tcx, obligation.param_env).into(), Vec::new()) } else if lang_items.pointee_trait() == Some(trait_def_id) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 16ee9fadab4fc..5f2a894413529 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,4 +1,5 @@ use rustc_infer::traits::{TraitEngine, TraitEngineExt}; +use rustc_macros::extension; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c520e699bf542..8b39c23da56b2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -13,6 +13,7 @@ use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; +use rustc_macros::extension; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 423ed0f7105be..f7e84a46639d4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -7,6 +7,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::OutlivesBound; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 07587e3741181..3e7aa52dcfeac 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -3,6 +3,7 @@ use crate::traits::query::dropck_outlives::{ compute_dropck_outlives_inner, trivial_dropck_outlives, }; use crate::traits::ObligationCtxt; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution}; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c415d288b8f71..40d206b92b8df 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -81,6 +81,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.discriminant_kind_trait() == Some(def_id) { // `DiscriminantKind` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); + } else if lang_items.async_destruct_trait() == Some(def_id) { + // `AsyncDestruct` is automatically implemented for every type. + candidates.vec.push(BuiltinCandidate { has_nested: false }); } else if lang_items.pointee_trait() == Some(def_id) { // `Pointee` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index fc12fed353738..18cb3184fe114 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1497,7 +1497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // bound regions. let trait_ref = predicate.skip_binder().trait_ref; - coherence::trait_ref_is_knowable::(self.tcx(), trait_ref, |ty| Ok(ty)).unwrap() + coherence::trait_ref_is_knowable::(self.infcx, trait_ref, |ty| Ok(ty)).unwrap() } /// Returns `true` if the global caches can be used. @@ -2001,7 +2001,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // any associated items and there are no where-clauses. // // We can just arbitrarily drop one of the impls. - Some(ty::ImplOverlapKind::Issue33140) => { + Some(ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects) => { assert_eq!(other.evaluation, victim.evaluation); DropVictim::Yes } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 46a0a4eb5ef8f..390e711a18d95 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -453,7 +453,7 @@ fn report_conflicting_impls<'tcx>( overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)", + Some(FutureCompatOverlapErrorKind::OrderDepTraitObjects) => ": (E0119)", _ => "", } ) @@ -480,7 +480,7 @@ fn report_conflicting_impls<'tcx>( } Some(kind) => { let lint = match kind { - FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS, + FutureCompatOverlapErrorKind::OrderDepTraitObjects => ORDER_DEPENDENT_TRAIT_OBJECTS, FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; tcx.node_span_lint( diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index dba014d58b00d..b6c2fcb46eb8a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -3,6 +3,7 @@ use super::OverlapError; use crate::traits; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; +use rustc_macros::extension; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -10,7 +11,7 @@ pub use rustc_middle::traits::specialization_graph::*; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { - Issue33140, + OrderDepTraitObjects, LeakCheck, } @@ -149,10 +150,10 @@ impl<'tcx> Children { { match overlap_kind { ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::Issue33140 => { + ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects => { *last_lint_mut = Some(FutureCompatOverlapError { error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::Issue33140, + kind: FutureCompatOverlapErrorKind::OrderDepTraitObjects, }); } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 5746e20490d00..64ab8378abb00 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -1,6 +1,7 @@ use rustc_infer::infer::at::At; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::traits::{FulfillmentError, TraitEngine}; +use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; use crate::traits::{NormalizeExt, Obligation}; diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index a8ca7d164a092..b2ba7854f1888 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_span::Span; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; pub use rustc_infer::traits::util::*; diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 46a68508753c0..178f3c63ef73c 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_span::{sym, Span}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::fmt::Debug; use std::ops::ControlFlow; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f1c24b6adc1ac..28ee76f7145c2 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() { cause = cause.derived_cause( parent_trait_pred, - traits::ObligationCauseCode::DerivedObligation, + traits::ObligationCauseCode::WellFormedDerivedObligation, ); } extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate); diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index b2b5c6cd9096f..51f38964415b0 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -5,6 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; +use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -12,6 +13,7 @@ use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, Unimplemented, }; +use tracing::debug; /// Attempts to resolve an obligation to an `ImplSource`. The result is /// a shallow `ImplSource` resolution, meaning that we do not diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index f40c3614e1c00..55abd6098ec97 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::GenericArgs; @@ -11,6 +12,7 @@ use rustc_trait_selection::traits::query::dropck_outlives::{ compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, }; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; +use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index ce22da23fffd3..c9ad096c6e9d0 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -6,6 +6,7 @@ use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, }; +use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { evaluate_obligation, ..*p }; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index e73bbf6048ece..bc5436f76f1cd 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,11 +2,6 @@ #![recursion_limit = "256"] -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_middle; - mod codegen; mod dropck_outlives; mod evaluate_obligation; diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 0576fe0102785..c5ebc2d26a794 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -4,6 +4,7 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; +use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 92a19fb91198c..559c05eb3e784 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -10,6 +10,7 @@ use rustc_trait_selection::traits::query::{ use rustc_trait_selection::traits::{ self, FulfillmentErrorCode, ObligationCause, SelectionContext, }; +use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index 77d5a48f15847..3378d1c6754db 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -2,6 +2,7 @@ use super::{nfa, Byte, Nfa, Ref}; use crate::Map; use std::fmt; use std::sync::atomic::{AtomicU32, Ordering}; +use tracing::instrument; #[derive(PartialEq, Clone, Debug)] pub(crate) struct Dfa diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index edd3227210b25..604b68d2cd4a6 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -266,7 +266,7 @@ pub(crate) mod rustc { ty::Ref(lifetime, ty, mutability) => { let ty_and_layout = cx.layout_of(*ty)?; - let align = ty_and_layout.align.abi.bytes() as usize; + let align = ty_and_layout.align.abi.bytes_usize(); let size = ty_and_layout.size.bytes_usize(); Ok(Tree::Ref(Ref { lifetime: *lifetime, diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 12312271646e2..8d7d81d8f7350 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -2,9 +2,6 @@ #![feature(never_type)] #![allow(unused_variables)] -#[macro_use] -extern crate tracing; - pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; pub mod layout; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 2789fe8f6b1db..dee5a72c3bcca 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -1,3 +1,5 @@ +use tracing::{debug, instrument, trace}; + pub(crate) mod query_context; #[cfg(test)] mod tests; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f0cea1f0baf38..c6b8362850663 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -854,7 +854,7 @@ fn make_thin_self_ptr<'tcx>( // we now have a type like `*mut RcBox` // change its layout to that of `*mut ()`, a thin pointer, but keep the same type // this is understood as a special case elsewhere in the compiler - let unit_ptr_ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)); + let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit); TyAndLayout { ty: fat_pointer_ty, diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 51b908881eb49..cb95239e99192 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -22,6 +22,17 @@ fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) is_item_raw(tcx, query, LangItem::Unpin) } +fn has_surface_async_drop_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> bool { + is_item_raw(tcx, query, LangItem::AsyncDrop) +} + +fn has_surface_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, LangItem::Drop) +} + fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -34,5 +45,13 @@ fn is_item_raw<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; + *providers = Providers { + is_copy_raw, + is_sized_raw, + is_freeze_raw, + is_unpin_raw, + has_surface_async_drop_raw, + has_surface_drop_raw, + ..*providers + }; } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index a8f9afb87dd7d..d0aa4eb2e714a 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -54,6 +54,28 @@ fn resolve_instance<'tcx>( debug!(" => trivial drop glue"); ty::InstanceDef::DropGlue(def_id, None) } + } else if Some(def_id) == tcx.lang_items().async_drop_in_place_fn() { + let ty = args.type_at(0); + + if !ty.is_async_destructor_noop(tcx, param_env) { + match *ty.kind() { + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::Tuple(..) + | ty::Adt(..) + | ty::Dynamic(..) + | ty::Array(..) + | ty::Slice(..) => {} + // Async destructor ctor shims can only be built from ADTs. + _ => return Ok(None), + } + debug!(" => nontrivial async drop glue ctor"); + ty::InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)) + } else { + debug!(" => trivial async drop glue ctor"); + ty::InstanceDef::AsyncDropGlueCtorShim(def_id, None) + } } else { debug!(" => free item"); // FIXME(effects): we may want to erase the effect param if that is present on this item. @@ -79,18 +101,11 @@ fn resolve_associated_item<'tcx>( let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) { Ok(vtbl) => vtbl, - Err(CodegenObligationError::Ambiguity) => { - let reported = tcx.dcx().span_delayed_bug( - tcx.def_span(trait_item_id), - format!( - "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ - overflow or prior type error", - ), - ); - return Err(reported); - } - Err(CodegenObligationError::Unimplemented) => return Ok(None), - Err(CodegenObligationError::FulfillmentError) => return Ok(None), + Err( + CodegenObligationError::Ambiguity + | CodegenObligationError::Unimplemented + | CodegenObligationError::FulfillmentError, + ) => return Ok(None), }; // Now that we know which impl is being used, we can dispatch to diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index a652bb781161c..d7d31a88c9b51 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -130,7 +130,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { TaitInBodyFinder { collector: self }.visit_expr(body); } - fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) { + fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) { if !self.seen.insert(alias_ty.def_id.expect_local()) { return; } @@ -205,7 +205,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { #[instrument(skip(self), ret, level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) { t.super_visit_with(self); - match t.kind() { + match *t.kind() { ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { self.visit_opaque_ty(alias_ty); } @@ -279,7 +279,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { // assumption to the `param_env` of the default method. We also separately // rely on that assumption here. let ty = self.tcx.type_of(alias_ty.def_id).instantiate(self.tcx, alias_ty.args); - let ty::Alias(ty::Opaque, alias_ty) = ty.kind() else { bug!("{ty:?}") }; + let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!("{ty:?}") }; self.visit_opaque_ty(alias_ty); } } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2139b8c665bf4..fa1085c7cd79a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -243,37 +243,39 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE tcx.param_env(def_id).with_reveal_all_normalized(tcx) } -/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`. +/// If the given trait impl enables exploiting the former order dependence of trait objects, +/// returns its self type; otherwise, returns `None`. /// -/// See [`ty::ImplOverlapKind::Issue33140`] for more details. -fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { - debug!("issue33140_self_ty({:?})", def_id); - - let impl_ = tcx - .impl_trait_header(def_id) - .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id)); +/// See [`ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects`] for more details. +#[instrument(level = "debug", skip(tcx))] +fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> Option>> { + let impl_ = + tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}")); let trait_ref = impl_.trait_ref.skip_binder(); - debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); + debug!(?trait_ref); let is_marker_like = impl_.polarity == ty::ImplPolarity::Positive && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); // Check whether these impls would be ok for a marker trait. if !is_marker_like { - debug!("issue33140_self_ty - not marker-like!"); + debug!("not marker-like!"); return None; } // impl must be `impl Trait for dyn Marker1 + Marker2 + ...` if trait_ref.args.len() != 1 { - debug!("issue33140_self_ty - impl has args!"); + debug!("impl has args!"); return None; } let predicates = tcx.predicates_of(def_id); if predicates.parent.is_some() || !predicates.predicates.is_empty() { - debug!("issue33140_self_ty - impl has predicates {:?}!", predicates); + debug!(?predicates, "impl has predicates!"); return None; } @@ -284,10 +286,10 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option { /// /// ``` /// #![feature(coroutines)] - /// static |a| { + /// #[coroutine] static |a| { /// let x = &vec![3]; /// yield a; /// yield x[0]; @@ -227,7 +229,7 @@ pub enum TyKind { /// A placeholder type, used during higher ranked subtyping to instantiate /// bound variables. /// - /// It is conventional to render anonymous placeholer types like `!N` or `!U_N`, + /// It is conventional to render anonymous placeholder types like `!N` or `!U_N`, /// where `N` is the placeholder variable's anonymous index (which corresponds /// to the bound variable's index from the binder from which it was instantiated), /// and `U` is the universe index in which it is instantiated, or totally omitted diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 94c552199bc5f..231d9ba49a39c 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -158,6 +158,9 @@ pub trait Context { /// Check if this is an empty DropGlue shim. fn is_empty_drop_shim(&self, def: InstanceDef) -> bool; + /// Check if this is an empty AsyncDropGlueCtor shim. + fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool; + /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. fn mono_instance(&self, def_id: DefId) -> Instance; @@ -218,7 +221,7 @@ pub trait Context { // A thread local variable that stores a pointer to the tables mapping between TyCtxt // datastructures and stable MIR datastructures -scoped_thread_local!(static TLV: Cell<*const ()>); +scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>); pub fn run(context: &dyn Context, f: F) -> Result where diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index d1a2948ea77ca..d9f988935ab19 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -16,8 +16,6 @@ //! //! The goal is to eventually be published on //! [crates.io](https://crates.io). -#[macro_use] -extern crate scoped_tls; use std::fmt; use std::fmt::Debug; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 6f666406c2210..e077c58031806 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -867,11 +867,9 @@ pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. This is used to prevent match guards from replacing - /// the scrutinee. For example, a fake borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. - Fake, + /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either + /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]). + Fake(FakeBorrowKind), /// Data is mutable and not aliasable. Mut { @@ -886,7 +884,7 @@ impl BorrowKind { BorrowKind::Mut { .. } => Mutability::Mut, BorrowKind::Shared => Mutability::Not, // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. - BorrowKind::Fake => Mutability::Not, + BorrowKind::Fake(_) => Mutability::Not, } } } @@ -898,6 +896,17 @@ pub enum MutBorrowKind { ClosureCapture, } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum FakeBorrowKind { + /// A shared (deep) borrow. Data must be immutable and is aliasable. + Deep, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. This is used to prevent match guards from replacing + /// the scrutinee. For example, a fake borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Mutability { Not, diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index a032a180fcfdd..394038926f61a 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -157,7 +157,10 @@ impl Instance { /// When generating code for a Drop terminator, users can ignore an empty drop glue. /// These shims are only needed to generate a valid Drop call done via VTable. pub fn is_empty_shim(&self) -> bool { - self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def)) + self.kind == InstanceKind::Shim + && with(|cx| { + cx.is_empty_drop_shim(self.def) || cx.is_empty_async_drop_ctor_shim(self.def) + }) } /// Try to constant evaluate the instance into a constant with the given type. diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 4ac4833add715..bbca3965852a6 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -8,7 +8,7 @@ use std::{fmt, io, iter}; use super::{AssertMessage, BinOp, TerminatorKind}; -use super::BorrowKind; +use super::{BorrowKind, FakeBorrowKind}; impl Display for Ty { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -352,7 +352,8 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { Rvalue::Ref(_, borrowkind, place) => { let kind = match borrowkind { BorrowKind::Shared => "&", - BorrowKind::Fake => "&fake ", + BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ", + BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ", BorrowKind::Mut { .. } => "&mut ", }; write!(writer, "{kind}{:?}", place) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index c54f0062824a1..846b9a1404d27 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -31,7 +31,7 @@ //! // instead of a max-heap. //! impl Ord for State { //! fn cmp(&self, other: &Self) -> Ordering { -//! // Notice that the we flip the ordering on costs. +//! // Notice that we flip the ordering on costs. //! // In case of a tie we compare positions - this step is necessary //! // to make implementations of `PartialEq` and `Ord` consistent. //! other.cost.cmp(&self.cost) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dec04d7e421e3..b93936869b3fd 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -126,10 +126,8 @@ #![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] -#![feature(generic_nonzero)] #![feature(hasher_prefixfree_extras)] #![feature(hint_assert_unchecked)] -#![feature(inline_const)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] @@ -139,7 +137,6 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] -#![feature(non_null_convenience)] #![feature(panic_internals)] #![feature(pattern)] #![feature(ptr_internals)] @@ -163,14 +160,11 @@ #![feature(tuple_trait)] #![feature(unicode_internals)] #![feature(unsize)] -#![feature(utf8_chunks)] #![feature(vec_pop_if)] // tidy-alphabetical-end // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(associated_type_bounds))] -#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] #![cfg_attr(not(test), feature(coroutine_trait))] #![cfg_attr(test, feature(panic_update_hook))] #![cfg_attr(test, feature(test))] @@ -201,6 +195,7 @@ #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(with_negative_coherence)] +#![rustc_preserve_ub_checks] // tidy-alphabetical-end // // Rustdoc features: diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0f81067b7a895..cbca5e7d98fb4 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3050,13 +3050,10 @@ impl Weak { /// [`as_ptr`]: Weak::as_ptr #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn into_raw_and_alloc(self) -> (*const T, A) - where - A: Clone, - { - let result = self.as_ptr(); - let alloc = self.alloc.clone(); - mem::forget(self); + pub fn into_raw_and_alloc(self) -> (*const T, A) { + let rc = mem::ManuallyDrop::new(self); + let result = rc.as_ptr(); + let alloc = unsafe { ptr::read(&rc.alloc) }; (result, alloc) } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index ade114678b7f9..c0d292cd20886 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -53,7 +53,7 @@ pub use core::str::{RSplit, Split}; pub use core::str::{RSplitN, SplitN}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitTerminator, SplitTerminator}; -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] pub use core::str::{Utf8Chunk, Utf8Chunks}; /// Note: `str` in `Concat` is not meaningful here. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 082af1447ece4..7c9f13e30ffb1 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -58,8 +58,6 @@ use core::ops::{self, Range, RangeBounds}; use core::ptr; use core::slice; use core::str::pattern::Pattern; -#[cfg(not(no_global_oom_handling))] -use core::str::Utf8Chunks; #[cfg(not(no_global_oom_handling))] use crate::borrow::{Cow, ToOwned}; @@ -633,7 +631,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { - let mut iter = Utf8Chunks::new(v); + let mut iter = v.utf8_chunks(); let first_valid = if let Some(chunk) = iter.next() { let valid = chunk.valid(); diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index a34bce66496d8..0eae4ca4b8ba3 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(allocator_api)] #![feature(alloc_layout_extra)] #![feature(iter_array_chunks)] @@ -14,7 +13,6 @@ #![feature(core_intrinsics)] #![feature(extract_if)] #![feature(exact_size_is_empty)] -#![feature(generic_nonzero)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] #![feature(new_uninit)] diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs index bb61224b5baad..3807cd5d76cfc 100644 --- a/library/core/benches/num/int_log/mod.rs +++ b/library/core/benches/num/int_log/mod.rs @@ -1,7 +1,7 @@ use rand::Rng; use test::{black_box, Bencher}; -macro_rules! int_log_bench { +macro_rules! int_log10_bench { ($t:ty, $predictable:ident, $random:ident, $random_small:ident) => { #[bench] fn $predictable(bench: &mut Bencher) { @@ -51,8 +51,75 @@ macro_rules! int_log_bench { }; } -int_log_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small} -int_log_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small} -int_log_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small} -int_log_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small} -int_log_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small} +int_log10_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small} +int_log10_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small} +int_log10_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small} +int_log10_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small} +int_log10_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small} + +macro_rules! int_log_bench { + ($t:ty, $random:ident, $random_small:ident, $geometric:ident) => { + #[bench] + fn $random(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS); + if x >= 2 { x } else { 2 } + }) + .collect(); + bench.iter(|| { + for &b in &numbers { + for &x in &numbers { + black_box(black_box(x).ilog(b)); + } + } + }); + } + + #[bench] + fn $random_small(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the range 0..256. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t; + if x >= 2 { x } else { 2 } + }) + .collect(); + bench.iter(|| { + for &b in &numbers { + for &x in &numbers { + black_box(black_box(x).ilog(b)); + } + } + }); + } + + #[bench] + fn $geometric(bench: &mut Bencher) { + let bases: [$t; 16] = [2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65]; + let base_and_numbers: Vec<($t, Vec<$t>)> = bases + .iter() + .map(|&b| { + let numbers = (0..=<$t>::MAX.ilog(b)).map(|exp| b.pow(exp)).collect(); + (b, numbers) + }) + .collect(); + bench.iter(|| { + for (b, numbers) in &base_and_numbers { + for &x in numbers { + black_box(black_box(x).ilog(black_box(*b))); + } + } + }); + } + }; +} + +int_log_bench! {u8, u8_log_random, u8_log_random_small, u8_log_geometric} +int_log_bench! {u16, u16_log_random, u16_log_random_small, u16_log_geometric} +int_log_bench! {u32, u32_log_random, u32_log_random_small, u32_log_geometric} +int_log_bench! {u64, u64_log_random, u64_log_random_small, u64_log_geometric} +int_log_bench! {u128, u128_log_random, u128_log_random_small, u128_log_geometric} diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2a02870e30be9..0b92767c93205 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -25,7 +25,9 @@ const fn size_align() -> (usize, usize) { /// An instance of `Layout` describes a particular layout of memory. /// You build a `Layout` up as an input to give to an allocator. /// -/// All layouts have an associated size and a power-of-two alignment. +/// All layouts have an associated size and a power-of-two alignment. The size, when rounded up to +/// the nearest multiple of `align`, does not overflow isize (i.e., the rounded value will always be +/// less than or equal to `isize::MAX`). /// /// (Note that layouts are *not* required to have non-zero size, /// even though `GlobalAlloc` requires that all memory requests diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 2a447aafe72d3..05874ab6c4cbb 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -512,7 +512,8 @@ impl [T; N] { /// # Examples /// /// ``` - /// #![feature(array_try_map, generic_nonzero)] + /// #![feature(array_try_map)] + /// /// let a = ["1", "2", "3"]; /// let b = a.try_map(|v| v.parse::()).unwrap().map(|v| v + 1); /// assert_eq!(b, [2, 3, 4]); @@ -522,8 +523,10 @@ impl [T; N] { /// assert!(b.is_err()); /// /// use std::num::NonZero; + /// /// let z = [1, 2, 0, 3, 4]; /// assert_eq!(z.try_map(NonZero::new), None); + /// /// let a = [1, 2, 3]; /// let b = a.try_map(NonZero::new); /// let c = b.map(|x| x.map(NonZero::get)); diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 2fd9e17c994fe..fc6022ab75357 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -379,7 +379,7 @@ pub struct AssertParamIsEq { // This is a lang item only so that `BinOp::Cmp` in MIR can return it. // It has no special behaviour, but does require that the three variants // `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively. -#[cfg_attr(not(bootstrap), lang = "Ordering")] +#[lang = "Ordering"] #[repr(i8)] pub enum Ordering { /// An ordering where a compared value is less than another. @@ -852,7 +852,7 @@ pub trait Ord: Eq + PartialOrd { #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_ord_max")] + #[rustc_diagnostic_item = "cmp_ord_max"] fn max(self, other: Self) -> Self where Self: Sized, @@ -873,7 +873,7 @@ pub trait Ord: Eq + PartialOrd { #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_ord_min")] + #[rustc_diagnostic_item = "cmp_ord_min"] fn min(self, other: Self) -> Self where Self: Sized, @@ -1160,7 +1160,7 @@ pub trait PartialOrd: PartialEq { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_cmp")] + #[rustc_diagnostic_item = "cmp_partialord_cmp"] fn partial_cmp(&self, other: &Rhs) -> Option; /// This method tests less than (for `self` and `other`) and is used by the `<` operator. @@ -1175,7 +1175,7 @@ pub trait PartialOrd: PartialEq { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_lt")] + #[rustc_diagnostic_item = "cmp_partialord_lt"] fn lt(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Less)) } @@ -1193,7 +1193,7 @@ pub trait PartialOrd: PartialEq { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_le")] + #[rustc_diagnostic_item = "cmp_partialord_le"] fn le(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Less | Equal)) } @@ -1210,7 +1210,7 @@ pub trait PartialOrd: PartialEq { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_gt")] + #[rustc_diagnostic_item = "cmp_partialord_gt"] fn gt(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Greater)) } @@ -1228,7 +1228,7 @@ pub trait PartialOrd: PartialEq { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialord_ge")] + #[rustc_diagnostic_item = "cmp_partialord_ge"] fn ge(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Greater | Equal)) } @@ -1558,14 +1558,7 @@ mod impls { impl PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { - #[cfg(bootstrap)] - { - Some(self.cmp(other)) - } - #[cfg(not(bootstrap))] - { - Some(crate::intrinsics::three_way_compare(*self, *other)) - } + Some(crate::intrinsics::three_way_compare(*self, *other)) } #[inline(always)] fn lt(&self, other: &$t) -> bool { (*self) < (*other) } @@ -1581,18 +1574,7 @@ mod impls { impl Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { - #[cfg(bootstrap)] - { - // The order here is important to generate more optimal assembly. - // See for more info. - if *self < *other { Less } - else if *self == *other { Equal } - else { Greater } - } - #[cfg(not(bootstrap))] - { - crate::intrinsics::three_way_compare(*self, *other) - } + crate::intrinsics::three_way_compare(*self, *other) } } )*) diff --git a/library/core/src/default.rs b/library/core/src/default.rs index e717a8d022fa6..4524b352ec817 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -178,9 +178,7 @@ default_impl! { i32, 0, "Returns the default value of `0`" } default_impl! { i64, 0, "Returns the default value of `0`" } default_impl! { i128, 0, "Returns the default value of `0`" } -#[cfg(not(bootstrap))] default_impl! { f16, 0.0f16, "Returns the default value of `0.0`" } default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" } default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" } -#[cfg(not(bootstrap))] default_impl! { f128, 0.0f128, "Returns the default value of `0.0`" } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index f4f33f8584bd0..aefb30463d33b 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -528,7 +528,7 @@ impl CStr { #[inline] #[must_use] #[doc(alias("len", "strlen"))] - #[stable(feature = "cstr_count_bytes", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "cstr_count_bytes", since = "1.79.0")] #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] pub const fn count_bytes(&self) -> usize { self.inner.len() - 1 diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index cbdae2ac76630..27dacbb23d958 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -213,7 +213,7 @@ impl fmt::Debug for c_void { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), + all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", windows, @@ -241,7 +241,7 @@ pub struct VaListImpl<'f> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), + all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", windows, @@ -265,7 +265,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[cfg(all( target_arch = "aarch64", - not(any(target_os = "macos", target_os = "ios", target_os = "tvos")), + not(target_vendor = "apple"), not(target_os = "uefi"), not(windows), ))] @@ -362,10 +362,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all( - target_arch = "aarch64", - any(target_os = "macos", target_os = "ios", target_os = "tvos") - ), + all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", windows, @@ -379,10 +376,7 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), - any( - not(target_arch = "aarch64"), - not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) - ), + any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), not(windows), @@ -399,7 +393,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), + all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", windows, @@ -425,10 +419,7 @@ impl<'f> VaListImpl<'f> { target_arch = "s390x", target_arch = "x86_64" ), - any( - not(target_arch = "aarch64"), - not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) - ), + any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), not(windows), diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 5e4dac8f49b6c..92626feabf3d7 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -153,7 +153,7 @@ impl<'a> Argument<'a> { /// /// # Safety /// - /// This argument must actually be a placeholer argument. + /// This argument must actually be a placeholder argument. /// // FIXME: Transmuting formatter in new and indirectly branching to/calling // it here is an explicit CFI violation. diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs new file mode 100644 index 0000000000000..0eb8d7bb32899 --- /dev/null +++ b/library/core/src/future/async_drop.rs @@ -0,0 +1,271 @@ +#![unstable(feature = "async_drop", issue = "none")] + +use crate::fmt; +use crate::future::{Future, IntoFuture}; +use crate::intrinsics::discriminant_value; +use crate::marker::{DiscriminantKind, PhantomPinned}; +use crate::mem::MaybeUninit; +use crate::pin::Pin; +use crate::task::{ready, Context, Poll}; + +/// Asynchronously drops a value by running `AsyncDrop::async_drop` +/// on a value and its fields recursively. +#[unstable(feature = "async_drop", issue = "none")] +pub fn async_drop(value: T) -> AsyncDropOwning { + AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned } +} + +/// A future returned by the [`async_drop`]. +#[unstable(feature = "async_drop", issue = "none")] +pub struct AsyncDropOwning { + value: MaybeUninit, + dtor: Option>, + _pinned: PhantomPinned, +} + +#[unstable(feature = "async_drop", issue = "none")] +impl fmt::Debug for AsyncDropOwning { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AsyncDropOwning").finish_non_exhaustive() + } +} + +#[unstable(feature = "async_drop", issue = "none")] +impl Future for AsyncDropOwning { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: Self is pinned thus it is ok to store references to self + unsafe { + let this = self.get_unchecked_mut(); + let dtor = Pin::new_unchecked( + this.dtor.get_or_insert_with(|| async_drop_in_place(this.value.as_mut_ptr())), + ); + // AsyncDestuctors are idempotent so Self gets idempotency as well + dtor.poll(cx) + } + } +} + +#[lang = "async_drop_in_place"] +#[allow(unconditional_recursion)] +// FIXME: Consider if `#[rustc_diagnostic_item = "ptr_drop_in_place"]` is needed? +unsafe fn async_drop_in_place_raw( + to_drop: *mut T, +) -> ::AsyncDestructor { + // Code here does not matter - this is replaced by the + // real async drop glue constructor by the compiler. + + // SAFETY: see comment above + unsafe { async_drop_in_place_raw(to_drop) } +} + +/// Creates the asynchronous destructor of the pointed-to value. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must be [valid](crate::ptr#safety) for both reads and writes. +/// +/// * `to_drop` must be properly aligned, even if `T` has size 0. +/// +/// * `to_drop` must be nonnull, even if `T` has size 0. +/// +/// * The value `to_drop` points to must be valid for async dropping, +/// which may mean it must uphold additional invariants. These +/// invariants depend on the type of the value being dropped. For +/// instance, when dropping a Box, the box's pointer to the heap must +/// be valid. +/// +/// * While `async_drop_in_place` is executing or the returned async +/// destructor is alive, the only way to access parts of `to_drop` +/// is through the `self: Pin<&mut Self>` references supplied to +/// the `AsyncDrop::async_drop` methods that `async_drop_in_place` +/// or `AsyncDropInPlace::poll` invokes. This usually means the +/// returned future stores the `to_drop` pointer and user is required +/// to guarantee that dropped value doesn't move. +/// +#[unstable(feature = "async_drop", issue = "none")] +pub unsafe fn async_drop_in_place(to_drop: *mut T) -> AsyncDropInPlace { + // SAFETY: `async_drop_in_place_raw` has the same safety requirements + unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) } +} + +/// A future returned by the [`async_drop_in_place`]. +#[unstable(feature = "async_drop", issue = "none")] +pub struct AsyncDropInPlace(::AsyncDestructor); + +#[unstable(feature = "async_drop", issue = "none")] +impl fmt::Debug for AsyncDropInPlace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AsyncDropInPlace").finish_non_exhaustive() + } +} + +#[unstable(feature = "async_drop", issue = "none")] +impl Future for AsyncDropInPlace { + type Output = (); + + #[inline(always)] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: This code simply forwards poll call to the inner future + unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }.poll(cx) + } +} + +// FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as +// with Drop impls +/// Custom code within the asynchronous destructor. +#[unstable(feature = "async_drop", issue = "none")] +#[lang = "async_drop"] +pub trait AsyncDrop { + /// A future returned by the [`AsyncDrop::async_drop`] to be part + /// of the async destructor. + #[unstable(feature = "async_drop", issue = "none")] + type Dropper<'a>: Future + where + Self: 'a; + + /// Constructs the asynchronous destructor for this type. + #[unstable(feature = "async_drop", issue = "none")] + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; +} + +#[lang = "async_destruct"] +#[rustc_deny_explicit_impl(implement_via_object = false)] +trait AsyncDestruct { + type AsyncDestructor: Future; +} + +/// Basically calls `AsyncDrop::async_drop` with pointer. Used to simplify +/// generation of the code for `async_drop_in_place_raw` +#[lang = "surface_async_drop_in_place"] +async unsafe fn surface_async_drop_in_place(ptr: *mut T) { + // SAFETY: We call this from async drop `async_drop_in_place_raw` + // which has the same safety requirements + unsafe { ::async_drop(Pin::new_unchecked(&mut *ptr)).await } +} + +/// Basically calls `Drop::drop` with pointer. Used to simplify generation +/// of the code for `async_drop_in_place_raw` +#[allow(drop_bounds)] +#[lang = "async_drop_surface_drop_in_place"] +async unsafe fn surface_drop_in_place(ptr: *mut T) { + // SAFETY: We call this from async drop `async_drop_in_place_raw` + // which has the same safety requirements + unsafe { crate::ops::fallback_surface_drop(&mut *ptr) } +} + +/// Wraps a future to continue outputing `Poll::Ready(())` once after +/// wrapped future completes by returning `Poll::Ready(())` on poll. This +/// is useful for constructing async destructors to guarantee this +/// "fuse" property +struct Fuse { + inner: Option, +} + +#[lang = "async_drop_fuse"] +fn fuse(inner: T) -> Fuse { + Fuse { inner: Some(inner) } +} + +impl Future for Fuse +where + T: Future, +{ + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: pin projection into `self.inner` + unsafe { + let this = self.get_unchecked_mut(); + if let Some(inner) = &mut this.inner { + ready!(Pin::new_unchecked(inner).poll(cx)); + this.inner = None; + } + } + Poll::Ready(()) + } +} + +/// Async destructor for arrays and slices. +#[lang = "async_drop_slice"] +async unsafe fn slice(s: *mut [T]) { + let len = s.len(); + let ptr = s.as_mut_ptr(); + for i in 0..len { + // SAFETY: we iterate over elements of `s` slice + unsafe { async_drop_in_place_raw(ptr.add(i)).await } + } +} + +/// Construct a chain of two futures, which awaits them sequentially as +/// a future. +#[lang = "async_drop_chain"] +async fn chain(first: F, last: G) +where + F: IntoFuture, + G: IntoFuture, +{ + first.await; + last.await; +} + +/// Basically a lazy version of `async_drop_in_place`. Returns a future +/// that would call `AsyncDrop::async_drop` on a first poll. +/// +/// # Safety +/// +/// Same as `async_drop_in_place` except is lazy to avoid creating +/// multiple mutable refernces. +#[lang = "async_drop_defer"] +async unsafe fn defer(to_drop: *mut T) { + // SAFETY: same safety requirements as `async_drop_in_place` + unsafe { async_drop_in_place(to_drop) }.await +} + +/// If `T`'s discriminant is equal to the stored one then awaits `M` +/// otherwise awaits the `O`. +/// +/// # Safety +/// +/// User should carefully manage returned future, since it would +/// try creating an immutable referece from `this` and get pointee's +/// discriminant. +// FIXME(zetanumbers): Send and Sync impls +#[lang = "async_drop_either"] +async unsafe fn either, M: IntoFuture, T>( + other: O, + matched: M, + this: *mut T, + discr: ::Discriminant, +) { + // SAFETY: Guaranteed by the safety section of this funtion's documentation + if unsafe { discriminant_value(&*this) } == discr { + drop(other); + matched.await + } else { + drop(matched); + other.await + } +} + +/// Used for noop async destructors. We don't use [`core::future::Ready`] +/// because it panics after its second poll, which could be potentially +/// bad if that would happen during the cleanup. +#[derive(Clone, Copy)] +struct Noop; + +#[lang = "async_drop_noop"] +fn noop() -> Noop { + Noop +} + +impl Future for Noop { + type Output = (); + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 0f77a2d83433f..873cccc7e96fd 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -12,6 +12,7 @@ use crate::ptr::NonNull; use crate::task::Context; +mod async_drop; mod future; mod into_future; mod join; @@ -36,6 +37,9 @@ pub use ready::{ready, Ready}; #[stable(feature = "future_poll_fn", since = "1.64.0")] pub use poll_fn::{poll_fn, PollFn}; +#[unstable(feature = "async_drop", issue = "none")] +pub use async_drop::{async_drop, async_drop_in_place, AsyncDrop, AsyncDropInPlace}; + /// This type is needed because: /// /// a) Coroutines cannot implement `for<'a, 'b> Coroutine<&'a mut Context<'b>>`, so we need to pass diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 92f1bd274082b..3318a8ffa5548 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1128,7 +1128,7 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1990,7 +1990,7 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] - pub fn ctpop(x: T) -> T; + pub fn ctpop(x: T) -> u32; /// Returns the number of leading unset bits (zeroes) in an integer type `T`. /// @@ -2031,7 +2031,7 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] - pub fn ctlz(x: T) -> T; + pub fn ctlz(x: T) -> u32; /// Like `ctlz`, but extra-unsafe as it returns `undef` when /// given an `x` with value `0`. @@ -2052,7 +2052,7 @@ extern "rust-intrinsic" { /// ``` #[rustc_const_stable(feature = "constctlz", since = "1.50.0")] #[rustc_nounwind] - pub fn ctlz_nonzero(x: T) -> T; + pub fn ctlz_nonzero(x: T) -> u32; /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. /// @@ -2093,7 +2093,7 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] - pub fn cttz(x: T) -> T; + pub fn cttz(x: T) -> u32; /// Like `cttz`, but extra-unsafe as it returns `undef` when /// given an `x` with value `0`. @@ -2114,7 +2114,7 @@ extern "rust-intrinsic" { /// ``` #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")] #[rustc_nounwind] - pub fn cttz_nonzero(x: T) -> T; + pub fn cttz_nonzero(x: T) -> u32; /// Reverses the bytes in an integer type `T`. /// @@ -2153,7 +2153,6 @@ extern "rust-intrinsic" { /// large and difficult to optimize. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. - #[cfg(not(bootstrap))] #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] #[rustc_safe_intrinsic] pub fn three_way_compare(lhs: T, rhs: T) -> crate::cmp::Ordering; @@ -2236,7 +2235,6 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] - #[cfg(not(bootstrap))] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] #[rustc_nounwind] pub fn unchecked_shl(x: T, y: U) -> T; @@ -2246,7 +2244,6 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] - #[cfg(not(bootstrap))] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] #[rustc_nounwind] pub fn unchecked_shr(x: T, y: U) -> T; @@ -2256,7 +2253,7 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[rustc_nounwind] pub fn unchecked_add(x: T, y: T) -> T; @@ -2265,7 +2262,7 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[rustc_nounwind] pub fn unchecked_sub(x: T, y: T) -> T; @@ -2274,7 +2271,7 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[rustc_nounwind] pub fn unchecked_mul(x: T, y: T) -> T; @@ -2291,7 +2288,7 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] - pub fn rotate_left(x: T, y: T) -> T; + pub fn rotate_left(x: T, shift: u32) -> T; /// Performs rotate right. /// @@ -2306,7 +2303,7 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] - pub fn rotate_right(x: T, y: T) -> T; + pub fn rotate_right(x: T, shift: u32) -> T; /// Returns (a + b) mod 2N, where N is the width of T in bits. /// @@ -2460,12 +2457,6 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] #[rustc_nounwind] pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; - - #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - #[cfg(bootstrap)] - pub fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8; } /// See documentation of `<*const T>::guaranteed_eq` for details. @@ -2475,7 +2466,6 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[cfg(not(bootstrap))] #[rustc_nounwind] #[rustc_do_not_const_check] #[inline] @@ -2534,28 +2524,6 @@ extern "rust-intrinsic" { #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn black_box(dummy: T) -> T; - - #[rustc_nounwind] - #[cfg(bootstrap)] - pub fn vtable_size(ptr: *const ()) -> usize; - - /// `ptr` must point to a vtable. - /// The intrinsic will return the alignment stored in that vtable. - #[rustc_nounwind] - #[cfg(bootstrap)] - pub fn vtable_align(ptr: *const ()) -> usize; - - #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] - #[rustc_safe_intrinsic] - #[cfg(bootstrap)] - pub fn const_eval_select( - arg: ARG, - called_in_const: F, - called_at_rt: G, - ) -> RET - where - G: FnOnce, - F: FnOnce; } /// Selects which function to call depending on the context. @@ -2590,11 +2558,9 @@ extern "rust-intrinsic" { /// #![feature(const_eval_select)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] -/// # #![cfg_attr(bootstrap, allow(unused))] /// use std::intrinsics::const_eval_select; /// /// // Standard library -/// # #[cfg(not(bootstrap))] /// pub const fn inconsistent() -> i32 { /// fn runtime() -> i32 { 1 } /// const fn compiletime() -> i32 { 2 } @@ -2603,8 +2569,6 @@ extern "rust-intrinsic" { /// // and `runtime`. /// const_eval_select((), compiletime, runtime) /// } -/// # #[cfg(bootstrap)] -/// # pub const fn inconsistent() -> i32 { 0 } /// /// // User Crate /// const X: i32 = inconsistent(); @@ -2616,7 +2580,6 @@ extern "rust-intrinsic" { /// otherwise, that principle should not be violated. #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg(not(bootstrap))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn const_eval_select( @@ -2670,10 +2633,45 @@ where /// particular value, ever. However, the compiler will generally make it /// return `true` only if the value of the argument is actually known. /// -/// When calling this in a `const fn`, both paths must be semantically -/// equivalent, that is, the result of the `true` branch and the `false` -/// branch must return the same value and have the same side-effects *no -/// matter what*. +/// # Stability concerns +/// +/// While it is safe to call, this intrinsic may behave differently in +/// a `const` context than otherwise. See the [`const_eval_select`] +/// documentation for an explanation of the issues this can cause. Unlike +/// `const_eval_select`, this intrinsic isn't guaranteed to behave +/// deterministically even in a `const` context. +/// +/// # Type Requirements +/// +/// `T` must be either a `bool`, a `char`, a primitive numeric type (e.g. `f32`, +/// but not `NonZeroISize`), or any thin pointer (e.g. `*mut String`). +/// Any other argument types *may* cause a compiler error. +/// +/// ## Pointers +/// +/// When the input is a pointer, only the pointer itself is +/// ever considered. The pointee has no effect. Currently, these functions +/// behave identically: +/// +/// ``` +/// #![feature(is_val_statically_known)] +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// #![feature(strict_provenance)] +/// use std::intrinsics::is_val_statically_known; +/// +/// fn foo(x: &i32) -> bool { +/// is_val_statically_known(x) +/// } +/// +/// fn bar(x: &i32) -> bool { +/// is_val_statically_known( +/// (x as *const i32).addr() +/// ) +/// } +/// # _ = foo(&5_i32); +/// # _ = bar(&5_i32); +/// ``` #[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] @@ -2694,7 +2692,7 @@ pub const fn is_val_statically_known(_arg: T) -> bool { /// `x` and `y` are readable and writable as `T`, and non-overlapping. #[rustc_nounwind] #[inline] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] // This has fallback `const fn` MIR, so shouldn't need stability, see #122652 #[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { @@ -2719,8 +2717,8 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] // just make it a regular fn in bootstrap -pub(crate) const fn ub_checks() -> bool { +#[rustc_intrinsic] +pub const fn ub_checks() -> bool { cfg!(debug_assertions) } @@ -2763,7 +2761,6 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] -#[cfg(not(bootstrap))] pub unsafe fn vtable_size(_ptr: *const ()) -> usize { unreachable!() } @@ -2774,7 +2771,6 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] -#[cfg(not(bootstrap))] pub unsafe fn vtable_align(_ptr: *const ()) -> usize { unreachable!() } @@ -2789,7 +2785,6 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] -#[cfg(not(bootstrap))] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { // To implement a fallback we'd have to assume the layout of the pointer, // but the whole point of this intrinsic is that we shouldn't do that. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index eeff4ec609a30..ceea67901294a 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -540,12 +540,8 @@ extern "rust-intrinsic" { /// `T` must be a vector of pointers. /// /// `U` must be a vector of `usize` with the same length as `T`. - #[cfg(not(bootstrap))] #[rustc_nounwind] pub fn simd_expose_provenance(ptr: T) -> U; - #[cfg(bootstrap)] - #[rustc_nounwind] - pub fn simd_expose_addr(ptr: T) -> U; /// Create a vector of pointers from a vector of addresses. /// @@ -553,11 +549,7 @@ extern "rust-intrinsic" { /// /// `U` must be a vector of pointers, with the same length as `T`. #[rustc_nounwind] - #[cfg(not(bootstrap))] pub fn simd_with_exposed_provenance(addr: T) -> U; - #[rustc_nounwind] - #[cfg(bootstrap)] - pub fn simd_from_exposed_addr(addr: T) -> U; /// Swap bytes of each element. /// @@ -663,8 +655,3 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_flog(a: T) -> T; } - -#[cfg(bootstrap)] -pub use simd_expose_addr as simd_expose_provenance; -#[cfg(bootstrap)] -pub use simd_from_exposed_addr as simd_with_exposed_provenance; diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index ef46040f0a703..7adbabf69e490 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -15,6 +15,7 @@ use crate::ops::Try; #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Enumerate")] pub struct Enumerate { iter: I, count: usize, diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 616dd0afc517d..a5cf069d407c0 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -515,9 +515,7 @@ macro_rules! spec_int_ranges_r { unsafe impl StepByBackImpl> for StepBy> { #[inline] - fn spec_next_back(&mut self) -> Option - where Range<$t>: DoubleEndedIterator + ExactSizeIterator, - { + fn spec_next_back(&mut self) -> Option { let step = self.original_step().get() as $t; let remaining = self.iter.end; if remaining > 0 { @@ -533,9 +531,7 @@ macro_rules! spec_int_ranges_r { // We have to repeat them here so that the specialization overrides the StepByImplBack defaults #[inline] - fn spec_nth_back(&mut self, n: usize) -> Option - where Self: DoubleEndedIterator, - { + fn spec_nth_back(&mut self, n: usize) -> Option { if self.advance_back_by(n).is_err() { return None; } @@ -544,10 +540,9 @@ macro_rules! spec_int_ranges_r { #[inline] fn spec_try_rfold(&mut self, init: Acc, mut f: F) -> R - where - Self: DoubleEndedIterator, - F: FnMut(Acc, Self::Item) -> R, - R: Try + where + F: FnMut(Acc, Self::Item) -> R, + R: Try { let mut accum = init; while let Some(x) = self.next_back() { @@ -558,9 +553,8 @@ macro_rules! spec_int_ranges_r { #[inline] fn spec_rfold(mut self, init: Acc, mut f: F) -> Acc - where - Self: DoubleEndedIterator, - F: FnMut(Acc, Self::Item) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc { let mut accum = init; while let Some(x) = self.next_back() { diff --git a/library/core/src/iter/sources/from_coroutine.rs b/library/core/src/iter/sources/from_coroutine.rs index bf413b24d4177..710ba504ded64 100644 --- a/library/core/src/iter/sources/from_coroutine.rs +++ b/library/core/src/iter/sources/from_coroutine.rs @@ -14,7 +14,7 @@ use crate::pin::Pin; /// #![feature(coroutines)] /// #![feature(iter_from_coroutine)] /// -/// let it = std::iter::from_coroutine(|| { +/// let it = std::iter::from_coroutine(#[coroutine] || { /// yield 1; /// yield 2; /// yield 3; diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 2ebbe2bf2743c..563781230c023 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -169,7 +169,7 @@ pub trait FromIterator: Sized { /// assert_eq!(lengths, [1, 1, 3, 1]); /// # Ok(()) } /// ``` -#[stable(feature = "from_iterator_for_tuple", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")] impl FromIterator<(AE, BE)> for (A, B) where A: Default + Extend, diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 35092ec51cdd9..3b12678572841 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -118,7 +118,8 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(generic_nonzero, iter_advance_by)] + /// #![feature(iter_advance_by)] + /// /// use std::num::NonZero; /// /// let a = [3, 4, 5, 6]; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 95c03043e3e8b..cee99e28b5a97 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -288,7 +288,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(generic_nonzero, iter_advance_by)] + /// #![feature(iter_advance_by)] + /// /// use std::num::NonZero; /// /// let a = [1, 2, 3, 4]; @@ -973,6 +974,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_do_not_const_check] + #[cfg_attr(not(test), rustc_diagnostic_item = "enumerate_method")] fn enumerate(self) -> Enumerate where Self: Sized, @@ -2939,7 +2941,8 @@ pub trait Iterator { /// This also supports other types which implement [`Try`], not just [`Result`]. /// /// ``` - /// #![feature(generic_nonzero, try_find)] + /// #![feature(try_find)] + /// /// use std::num::NonZero; /// /// let a = [3, 5, 7, 4, 9, 0, 11u32]; diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index ad4d63d83b5be..2e756a6dd67c4 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -28,7 +28,7 @@ pub unsafe trait TrustedFused {} #[rustc_unsafe_specialization_marker] // FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused // but that ICEs iter::Fuse specializations. -#[cfg_attr(not(bootstrap), lang = "fused_iterator")] +#[lang = "fused_iterator"] pub trait FusedIterator: Iterator {} #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 154565b6fee17..5dcef63895441 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -90,7 +90,7 @@ ))] #![no_core] #![rustc_coherence_is_core] -#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] +#![rustc_preserve_ub_checks] // // Lints: #![deny(rust_2021_incompatible_or_patterns)] @@ -109,7 +109,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(char_indices_offset)] @@ -180,7 +179,6 @@ #![feature(isqrt)] #![feature(link_cfg)] #![feature(maybe_uninit_uninit_array)] -#![feature(non_null_convenience)] #![feature(offset_of_enum)] #![feature(offset_of_nested)] #![feature(panic_internals)] @@ -193,6 +191,7 @@ #![feature(str_split_inclusive_remainder)] #![feature(str_split_remainder)] #![feature(strict_provenance)] +#![feature(ub_checks)] #![feature(unchecked_shifts)] #![feature(utf16_extra)] #![feature(utf16_extra_const)] @@ -231,7 +230,6 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] -#![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] @@ -370,7 +368,8 @@ pub mod hint; pub mod intrinsics; pub mod mem; pub mod ptr; -mod ub_checks; +#[unstable(feature = "ub_checks", issue = "none")] +pub mod ub_checks; /* Core language traits */ @@ -401,7 +400,6 @@ pub mod net; pub mod option; pub mod panic; pub mod panicking; -#[cfg(not(bootstrap))] #[unstable(feature = "core_pattern_types", issue = "none")] pub mod pat; pub mod pin; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6da05a1ca867a..2ddedfa37fe27 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1711,11 +1711,11 @@ pub(crate) mod builtin { issue = "23416", reason = "placeholder syntax for type ascription" )] + #[rustfmt::skip] pub macro type_ascribe($expr:expr, $ty:ty) { builtin # type_ascribe($expr, $ty) } - #[cfg(not(bootstrap))] /// Unstable placeholder for deref patterns. #[allow_internal_unstable(builtin_syntax)] #[unstable( diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 75d42edbaa033..9054ade2d7968 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1340,8 +1340,8 @@ impl SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` #[stable(feature = "offset_of", since = "1.77.0")] -#[allow_internal_unstable(builtin_syntax, hint_must_use)] +#[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { // The `{}` is for better error messages - crate::hint::must_use({builtin # offset_of($Container, $($fields)+)}) + {builtin # offset_of($Container, $($fields)+)} } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index de25b999bde5b..77b1039039b1d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -481,8 +481,8 @@ macro_rules! int_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")] #[doc = concat!("[`wrapping_add`]: ", stringify!($SelfT), "::wrapping_add")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -623,8 +623,8 @@ macro_rules! int_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")] #[doc = concat!("[`wrapping_sub`]: ", stringify!($SelfT), "::wrapping_sub")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -765,8 +765,8 @@ macro_rules! int_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")] #[doc = concat!("[`wrapping_mul`]: ", stringify!($SelfT), "::wrapping_mul")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1234,18 +1234,9 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { - #[cfg(bootstrap)] - { - // For bootstrapping, just use built-in primitive shift. - // panicking is a legal manifestation of UB - self << rhs - } - #[cfg(not(bootstrap))] - { // SAFETY: the caller must uphold the safety contract for // `unchecked_shl`. unsafe { intrinsics::unchecked_shl(self, rhs) } - } } /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is @@ -1332,18 +1323,9 @@ macro_rules! int_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { - #[cfg(bootstrap)] - { - // For bootstrapping, just use built-in primitive shift. - // panicking is a legal manifestation of UB - self >> rhs - } - #[cfg(not(bootstrap))] - { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shr`. - unsafe { intrinsics::unchecked_shr(self, rhs) } - } + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shr`. + unsafe { intrinsics::unchecked_shr(self, rhs) } } /// Checked absolute value. Computes `self.abs()`, returning `None` if @@ -3123,21 +3105,9 @@ macro_rules! int_impl { if self <= 0 || base <= 1 { None } else { - let mut n = 0; - let mut r = self; - - // Optimization for 128 bit wide integers. - if Self::BITS == 128 { - let b = Self::ilog2(self) / (Self::ilog2(base) + 1); - n += b; - r /= base.pow(b as u32); - } - - while r >= base { - r /= base; - n += 1; - } - Some(n) + // Delegate to the unsigned implementation. + // The condition makes sure that both casts are exact. + (self as $UnsignedT).checked_ilog(base as $UnsignedT) } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 9ebbb4ffe80b5..c02f73fdf0364 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -67,15 +67,15 @@ pub use error::ParseIntError; )] pub use nonzero::ZeroablePrimitive; -#[unstable(feature = "generic_nonzero", issue = "120257")] +#[stable(feature = "generic_nonzero", since = "1.79.0")] pub use nonzero::NonZero; -#[stable(feature = "nonzero", since = "1.28.0")] -pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; - #[stable(feature = "signed_nonzero", since = "1.34.0")] pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +#[stable(feature = "nonzero", since = "1.28.0")] +pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + #[stable(feature = "try_from", since = "1.34.0")] pub use error::TryFromIntError; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 62ea7abf6528a..5d3ae7316b124 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -105,12 +105,11 @@ impl_zeroable_primitive!( /// For example, `Option>` is the same size as `u32`: /// /// ``` -/// #![feature(generic_nonzero)] -/// use core::mem::size_of; +/// use core::{mem::size_of, num::NonZero}; /// -/// assert_eq!(size_of::>>(), size_of::()); +/// assert_eq!(size_of::>>(), size_of::()); /// ``` -#[unstable(feature = "generic_nonzero", issue = "120257")] +#[stable(feature = "generic_nonzero", since = "1.79.0")] #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonZero"] @@ -528,7 +527,9 @@ macro_rules! nonzero_integer { #[inline] pub const fn leading_zeros(self) -> u32 { // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`. - unsafe { intrinsics::ctlz_nonzero(self.get() as $UnsignedPrimitive) as u32 } + unsafe { + intrinsics::ctlz_nonzero(self.get() as $UnsignedPrimitive) + } } /// Returns the number of trailing zeros in the binary representation @@ -552,7 +553,9 @@ macro_rules! nonzero_integer { #[inline] pub const fn trailing_zeros(self) -> u32 { // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. - unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 } + unsafe { + intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) + } } /// Returns the number of ones in the binary representation of `self`. @@ -562,7 +565,8 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - /// #![feature(generic_nonzero, non_zero_count_ones)] + /// #![feature(non_zero_count_ones)] + /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { /// # use std::num::*; @@ -851,7 +855,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { } } - #[stable(feature = "nonzero_div_assign", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_div_assign", since = "1.79.0")] impl DivAssign<$Ty> for $Int { /// This operation rounds towards zero, /// truncating any fractional part of the exact result, and cannot panic. @@ -874,7 +878,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { } } - #[stable(feature = "nonzero_div_assign", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_div_assign", since = "1.79.0")] impl RemAssign<$Ty> for $Int { /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 58f713baa57b4..9effa279b48e1 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -77,7 +77,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline(always)] pub const fn count_ones(self) -> u32 { - intrinsics::ctpop(self as $ActualT) as u32 + return intrinsics::ctpop(self as $ActualT); } /// Returns the number of zeros in the binary representation of `self`. @@ -119,7 +119,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline(always)] pub const fn leading_zeros(self) -> u32 { - intrinsics::ctlz(self as $ActualT) as u32 + return intrinsics::ctlz(self as $ActualT); } /// Returns the number of trailing zeros in the binary representation @@ -140,7 +140,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline(always)] pub const fn trailing_zeros(self) -> u32 { - intrinsics::cttz(self) as u32 + return intrinsics::cttz(self); } /// Returns the number of leading ones in the binary representation of `self`. @@ -205,7 +205,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline(always)] pub const fn rotate_left(self, n: u32) -> Self { - intrinsics::rotate_left(self, n as $SelfT) + return intrinsics::rotate_left(self, n); } /// Shifts the bits to the right by a specified amount, `n`, @@ -230,7 +230,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline(always)] pub const fn rotate_right(self, n: u32) -> Self { - intrinsics::rotate_right(self, n as $SelfT) + return intrinsics::rotate_right(self, n); } /// Reverses the byte order of the integer. @@ -488,8 +488,8 @@ macro_rules! uint_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")] #[doc = concat!("[`wrapping_add`]: ", stringify!($SelfT), "::wrapping_add")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -645,8 +645,8 @@ macro_rules! uint_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")] #[doc = concat!("[`wrapping_sub`]: ", stringify!($SelfT), "::wrapping_sub")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -731,8 +731,8 @@ macro_rules! uint_impl { /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")] #[doc = concat!("[`wrapping_mul`]: ", stringify!($SelfT), "::wrapping_mul")] - #[stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unchecked_math", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unchecked_math", since = "1.79.0")] + #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1095,18 +1095,25 @@ macro_rules! uint_impl { None } else { let mut n = 0; - let mut r = self; + let mut r = 1; // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::ilog2(self) / (Self::ilog2(base) + 1); - n += b; - r /= base.pow(b as u32); + // The following is a correct lower bound for ⌊log(base,self)⌋ because + // + // log(base,self) = log(2,self) / log(2,base) + // ≥ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1) + // + // hence + // + // ⌊log(base,self)⌋ ≥ ⌊ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1) ⌋ . + n = self.ilog2() / (base.ilog2() + 1); + r = base.pow(n); } - while r >= base { - r /= base; + while r <= self / base { n += 1; + r *= base; } Some(n) } @@ -1302,18 +1309,9 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { - #[cfg(bootstrap)] - { - // For bootstrapping, just use built-in primitive shift. - // panicking is a legal manifestation of UB - self << rhs - } - #[cfg(not(bootstrap))] - { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_shl`. - unsafe { intrinsics::unchecked_shl(self, rhs) } - } + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shl`. + unsafe { intrinsics::unchecked_shl(self, rhs) } } /// Checked shift right. Computes `self >> rhs`, returning `None` @@ -1400,18 +1398,9 @@ macro_rules! uint_impl { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { - #[cfg(bootstrap)] - { - // For bootstrapping, just use built-in primitive shift. - // panicking is a legal manifestation of UB - self >> rhs - } - #[cfg(not(bootstrap))] - { // SAFETY: the caller must uphold the safety contract for // `unchecked_shr`. unsafe { intrinsics::unchecked_shr(self, rhs) } - } } /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 6e067f95da92d..6a6c5db1ab115 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -40,12 +40,13 @@ pub enum CoroutineState { /// ```rust /// #![feature(coroutines)] /// #![feature(coroutine_trait)] +/// #![feature(stmt_expr_attributes)] /// /// use std::ops::{Coroutine, CoroutineState}; /// use std::pin::Pin; /// /// fn main() { -/// let mut coroutine = || { +/// let mut coroutine = #[coroutine] || { /// yield 1; /// "foo" /// }; diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 3795a81c2c151..9849410d484ca 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -285,7 +285,7 @@ impl DerefMut for &mut T { /// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise /// unchanged. #[unstable(feature = "deref_pure_trait", issue = "87121")] -#[cfg_attr(not(bootstrap), lang = "deref_pure")] +#[lang = "deref_pure"] pub unsafe trait DerefPure {} #[unstable(feature = "deref_pure_trait", issue = "87121")] diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 34dfa9e4c51fc..36ae581e3f723 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -238,3 +238,10 @@ pub trait Drop { #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } + +/// Fallback function to call surface level `Drop::drop` function +#[allow(drop_bounds)] +#[lang = "fallback_surface_drop"] +pub(crate) fn fallback_surface_drop(x: &mut T) { + ::drop(x) +} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index ac808bec50ece..7bcfaadbe372b 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -174,6 +174,8 @@ pub use self::deref::Receiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::drop::Drop; +pub(crate) use self::drop::fallback_surface_drop; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 631e1654ce075..1e3ed0f7c49f1 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -554,7 +554,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FusedIterator, TrustedLen}; -use crate::panicking::{panic, panic_str}; +use crate::panicking::{panic, panic_display}; use crate::pin::Pin; use crate::{ cmp, convert, hint, mem, @@ -1991,7 +1991,7 @@ const fn unwrap_failed() -> ! { #[track_caller] #[rustc_const_unstable(feature = "const_option", issue = "67441")] const fn expect_failed(msg: &str) -> ! { - panic_str(msg) + panic_display(&msg) } ///////////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index b520efe93f90d..8771f40f9b42b 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -27,9 +27,9 @@ pub macro panic_2015 { ($msg:literal $(,)?) => ( $crate::panicking::panic($msg) ), - // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. + // Use `panic_str_2015` instead of `panic_display::<&str>` for non_fmt_panic lint. ($msg:expr $(,)?) => ({ - $crate::panicking::panic_str($msg); + $crate::panicking::panic_str_2015($msg); }), // Special-case the single-argument case for const_panic. ("{}", $arg:expr $(,)?) => ({ diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 4ad507d8b868b..eb27da1724ec9 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -81,7 +81,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")] #[track_caller] #[inline] pub const fn caller() -> &'static Location<'static> { @@ -123,7 +123,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")] #[inline] pub const fn file(&self) -> &str { self.file @@ -148,7 +148,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")] #[inline] pub const fn line(&self) -> u32 { self.line @@ -173,7 +173,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_col", since = "1.25.0")] - #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")] #[inline] pub const fn column(&self) -> u32 { self.col diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index cbb0a7d61db05..ca06e059b75ac 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -124,8 +124,8 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // above. /// The underlying implementation of core's `panic!` macro when no formatting is used. -// never inline unless panic_immediate_abort to avoid code -// bloat at the call sites as much as possible +// Never inline unless panic_immediate_abort to avoid code +// bloat at the call sites as much as possible. #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] @@ -138,6 +138,11 @@ pub const fn panic(expr: &'static str) -> ! { // truncation and padding (even though none is used here). Using // Arguments::new_const may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. + // However, this optimization only works for `'static` strings: `new_const` also makes this + // message return `Some` from `Arguments::as_str`, which means it can become part of the panic + // payload without any allocation or copying. Shorter-lived strings would become invalid as + // stack frames get popped during unwinding, and couldn't be directly referenced from the + // payload. panic_fmt(fmt::Arguments::new_const(&[expr])); } @@ -151,7 +156,6 @@ pub const fn panic(expr: &'static str) -> ! { // reducing binary size impact. macro_rules! panic_const { ($($lang:ident = $message:expr,)+) => { - #[cfg(not(bootstrap))] pub mod panic_const { use super::*; @@ -223,14 +227,6 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); } -#[inline] -#[track_caller] -#[rustc_diagnostic_item = "panic_str"] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] -pub const fn panic_str(expr: &str) -> ! { - panic_display(&expr); -} - #[track_caller] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] @@ -246,6 +242,16 @@ pub fn unreachable_display(x: &T) -> ! { panic_fmt(format_args!("internal error: entered unreachable code: {}", *x)); } +/// This exists solely for the 2015 edition `panic!` macro to trigger +/// a lint on `panic!(my_str_variable);`. +#[inline] +#[track_caller] +#[rustc_diagnostic_item = "panic_str_2015"] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +pub const fn panic_str_2015(expr: &str) -> ! { + panic_display(&expr); +} + #[inline] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index efd525aeb3b74..f7463d170fd8e 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1809,7 +1809,7 @@ impl DispatchFromDyn> for Pin where Ptr: DispatchFromDyn /// fn coroutine_fn() -> impl Coroutine /* not Unpin */ { /// // Allow coroutine to be self-referential (not `Unpin`) /// // vvvvvv so that locals can cross yield points. -/// static || { +/// #[coroutine] static || { /// let foo = String::from("foo"); /// let foo_ref = &foo; // ------+ /// yield 0; // | <- crosses yield point! diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index b98f3a4659b10..afc6817aa1d24 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -97,7 +97,6 @@ pub use crate::macros::builtin::cfg_eval; )] pub use crate::macros::builtin::type_ascribe; -#[cfg(not(bootstrap))] #[unstable( feature = "deref_patterns", issue = "87121", diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index bda1ee6f45712..18a9503cfd2f5 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -268,6 +268,53 @@ mod prim_bool {} /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// +/// # Never type fallback +/// +/// When the compiler sees a value of type `!` in a [coercion site], it implicitly inserts a +/// coercion to allow the type checker to infer any type: +/// +/// ```rust,ignore (illustrative-and-has-placeholders) +/// // this +/// let x: u8 = panic!(); +/// +/// // is (essentially) turned by the compiler into +/// let x: u8 = absurd(panic!()); +/// +/// // where absurd is a function with the following signature +/// // (it's sound, because `!` always marks unreachable code): +/// fn absurd(_: !) -> T { ... } +// FIXME: use `core::convert::absurd` here instead, once it's merged +/// ``` +/// +/// This can lead to compilation errors if the type cannot be inferred: +/// +/// ```compile_fail +/// // this +/// { panic!() }; +/// +/// // gets turned into this +/// { absurd(panic!()) }; // error: can't infer the type of `absurd` +/// ``` +/// +/// To prevent such errors, the compiler remembers where it inserted `absurd` calls, and +/// if it can't infer the type, it uses the fallback type instead: +/// ```rust, ignore +/// type Fallback = /* An arbitrarily selected type! */; +/// { absurd::(panic!()) } +/// ``` +/// +/// This is what is known as "never type fallback". +/// +/// Historically, the fallback type was [`()`], causing confusing behavior where `!` spontaneously +/// coerced to `()`, even when it would not infer `()` without the fallback. There are plans to +/// change it in the [2024 edition] (and possibly in all editions on a later date); see +/// [Tracking Issue for making `!` fall back to `!`][fallback-ti]. +/// +/// [coercion site]: +/// [`()`]: prim@unit +/// [fallback-ti]: +/// [2024 edition]: +/// #[unstable(feature = "never_type", issue = "35121")] mod prim_never {} diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 9737fb8816e9c..e9eeb3153307f 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1496,7 +1496,7 @@ impl *const T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "pointer_is_aligned", since = "1.79.0")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned(self) -> bool where @@ -1653,8 +1653,8 @@ impl *const [T] { /// assert_eq!(slice.len(), 3); /// ``` #[inline] - #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_ptr_len", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) @@ -1671,8 +1671,8 @@ impl *const [T] { /// assert!(!slice.is_empty()); /// ``` #[inline(always)] - #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_ptr_len", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] pub const fn is_empty(self) -> bool { self.len() == 0 } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 1226c8e24194e..eb815b6d822c5 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -2,7 +2,6 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; -#[cfg(not(bootstrap))] use crate::intrinsics::aggregate_raw_ptr; use crate::marker::Freeze; @@ -115,17 +114,7 @@ pub const fn from_raw_parts( data_pointer: *const (), metadata: ::Metadata, ) -> *const T { - #[cfg(bootstrap)] - { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr } - } - #[cfg(not(bootstrap))] - { - aggregate_raw_ptr(data_pointer, metadata) - } + aggregate_raw_ptr(data_pointer, metadata) } /// Performs the same functionality as [`from_raw_parts`], except that a @@ -139,17 +128,7 @@ pub const fn from_raw_parts_mut( data_pointer: *mut (), metadata: ::Metadata, ) -> *mut T { - #[cfg(bootstrap)] - { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr } - } - #[cfg(not(bootstrap))] - { - aggregate_raw_ptr(data_pointer, metadata) - } + aggregate_raw_ptr(data_pointer, metadata) } #[repr(C)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f12ab3d50cdd4..5f3815859c8fa 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1784,15 +1784,6 @@ pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usiz assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub, }; - #[cfg(bootstrap)] - const unsafe fn unchecked_shl(value: usize, shift: usize) -> usize { - value << shift - } - #[cfg(bootstrap)] - const unsafe fn unchecked_shr(value: usize, shift: usize) -> usize { - value >> shift - } - #[cfg(not(bootstrap))] use intrinsics::{unchecked_shl, unchecked_shr}; /// Calculate multiplicative modular inverse of `x` modulo `m`. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d8f91f1996b92..c5a188dc7d4f2 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1756,7 +1756,7 @@ impl *mut T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "pointer_is_aligned", since = "1.79.0")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned(self) -> bool where @@ -1915,8 +1915,8 @@ impl *mut [T] { /// assert_eq!(slice.len(), 3); /// ``` #[inline(always)] - #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_ptr_len", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) @@ -1933,8 +1933,8 @@ impl *mut [T] { /// assert!(!slice.is_empty()); /// ``` #[inline(always)] - #[stable(feature = "slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_slice_ptr_len", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_ptr_len", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] pub const fn is_empty(self) -> bool { self.len() == 0 } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 96ce3cd3a3fb5..617890cf083b1 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -512,7 +512,6 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(non_null_convenience)] /// use std::ptr::NonNull; /// /// let mut s = [1, 2, 3]; @@ -523,12 +522,12 @@ impl NonNull { /// println!("{}", ptr.offset(2).read()); /// } /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - #[must_use = "returns a new pointer rather than modifying its argument"] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn offset(self, count: isize) -> NonNull + #[must_use = "returns a new pointer rather than modifying its argument"] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + pub const unsafe fn offset(self, count: isize) -> Self where T: Sized, { @@ -549,11 +548,11 @@ impl NonNull { /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has // the same safety contract. @@ -599,7 +598,6 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(non_null_convenience)] /// use std::ptr::NonNull; /// /// let s: &str = "123"; @@ -610,11 +608,11 @@ impl NonNull { /// println!("{}", ptr.add(2).read() as char); /// } /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - #[must_use = "returns a new pointer rather than modifying its argument"] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[must_use = "returns a new pointer rather than modifying its argument"] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -636,12 +634,12 @@ impl NonNull { /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[must_use] #[inline(always)] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_allow_const_fn_unstable(set_ptr_value)] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same // safety contract. @@ -688,7 +686,6 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(non_null_convenience)] /// use std::ptr::NonNull; /// /// let s: &str = "123"; @@ -699,11 +696,11 @@ impl NonNull { /// println!("{}", end.sub(2).read() as char); /// } /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - #[must_use = "returns a new pointer rather than modifying its argument"] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[must_use = "returns a new pointer rather than modifying its argument"] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -730,12 +727,12 @@ impl NonNull { /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[must_use] #[inline(always)] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_allow_const_fn_unstable(set_ptr_value)] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub` and `byte_sub` has the same // safety contract. @@ -816,7 +813,6 @@ impl NonNull { /// Basic usage: /// /// ``` - /// #![feature(non_null_convenience)] /// use std::ptr::NonNull; /// /// let a = [0; 5]; @@ -833,7 +829,7 @@ impl NonNull { /// *Incorrect* usage: /// /// ```rust,no_run - /// #![feature(non_null_convenience, strict_provenance)] + /// #![feature(strict_provenance)] /// use std::ptr::NonNull; /// /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap(); @@ -845,14 +841,13 @@ impl NonNull { /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though /// // they point to the same address! - /// unsafe { - /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior - /// } + /// + /// let zero = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn offset_from(self, origin: NonNull) -> isize where T: Sized, @@ -870,10 +865,10 @@ impl NonNull { /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn byte_offset_from(self, origin: NonNull) -> isize { // SAFETY: the caller must uphold the safety contract for `byte_offset_from`. unsafe { self.pointer.byte_offset_from(origin.pointer) } @@ -897,7 +892,7 @@ impl NonNull { /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: /// ```rust - /// # #![feature(non_null_convenience)] + /// # #![feature(ptr_sub_ptr)] /// # unsafe fn blah(ptr: std::ptr::NonNull, origin: std::ptr::NonNull, count: usize) -> bool { /// ptr.sub_ptr(origin) == count /// # && @@ -926,7 +921,7 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(non_null_convenience)] + /// #![feature(ptr_sub_ptr)] /// use std::ptr::NonNull; /// /// let a = [0; 5]; @@ -942,12 +937,10 @@ impl NonNull { /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.sub_ptr(ptr2) /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - // #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - // #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[unstable(feature = "ptr_sub_ptr", issue = "95892")] + #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] pub const unsafe fn sub_ptr(self, subtracted: NonNull) -> usize where T: Sized, @@ -962,10 +955,10 @@ impl NonNull { /// See [`ptr::read`] for safety concerns and examples. /// /// [`ptr::read`]: crate::ptr::read() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn read(self) -> T where T: Sized, @@ -984,9 +977,9 @@ impl NonNull { /// See [`ptr::read_volatile`] for safety concerns and examples. /// /// [`ptr::read_volatile`]: crate::ptr::read_volatile() - #[unstable(feature = "non_null_convenience", issue = "117691")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1003,10 +996,10 @@ impl NonNull { /// See [`ptr::read_unaligned`] for safety concerns and examples. /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1023,10 +1016,10 @@ impl NonNull { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_to(self, dest: NonNull, count: usize) where T: Sized, @@ -1043,10 +1036,10 @@ impl NonNull { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull, count: usize) where T: Sized, @@ -1063,10 +1056,10 @@ impl NonNull { /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_from(self, src: NonNull, count: usize) where T: Sized, @@ -1083,10 +1076,10 @@ impl NonNull { /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull, count: usize) where T: Sized, @@ -1100,8 +1093,8 @@ impl NonNull { /// See [`ptr::drop_in_place`] for safety concerns and examples. /// /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() - #[unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub unsafe fn drop_in_place(self) { // SAFETY: the caller must uphold the safety contract for `drop_in_place`. unsafe { ptr::drop_in_place(self.as_ptr()) } @@ -1113,11 +1106,10 @@ impl NonNull { /// See [`ptr::write`] for safety concerns and examples. /// /// [`ptr::write`]: crate::ptr::write() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write(self, val: T) where T: Sized, @@ -1132,12 +1124,11 @@ impl NonNull { /// See [`ptr::write_bytes`] for safety concerns and examples. /// /// [`ptr::write_bytes`]: crate::ptr::write_bytes() - #[doc(alias = "memset")] - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] + #[doc(alias = "memset")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1156,9 +1147,9 @@ impl NonNull { /// See [`ptr::write_volatile`] for safety concerns and examples. /// /// [`ptr::write_volatile`]: crate::ptr::write_volatile() - #[unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1175,11 +1166,10 @@ impl NonNull { /// See [`ptr::write_unaligned`] for safety concerns and examples. /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_unaligned(self, val: T) where T: Sized, @@ -1194,8 +1184,8 @@ impl NonNull { /// See [`ptr::replace`] for safety concerns and examples. /// /// [`ptr::replace`]: crate::ptr::replace() - #[unstable(feature = "non_null_convenience", issue = "117691")] #[inline(always)] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] pub unsafe fn replace(self, src: T) -> T where T: Sized, @@ -1211,10 +1201,9 @@ impl NonNull { /// See [`ptr::swap`] for safety concerns and examples. /// /// [`ptr::swap`]: crate::ptr::swap() - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - //#[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[inline(always)] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap(self, with: NonNull) where T: Sized, @@ -1246,7 +1235,6 @@ impl NonNull { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// #![feature(non_null_convenience)] /// use std::mem::align_of; /// use std::ptr::NonNull; /// @@ -1264,11 +1252,10 @@ impl NonNull { /// } /// # } /// ``` - #[unstable(feature = "non_null_convenience", issue = "117691")] - #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] - //#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - #[must_use] #[inline] + #[must_use] + #[stable(feature = "non_null_convenience", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] pub const fn align_offset(self, align: usize) -> usize where T: Sized, @@ -1312,10 +1299,9 @@ impl NonNull { /// underlying allocation. /// /// ``` - /// #![feature(const_pointer_is_aligned)] - /// #![feature(non_null_convenience)] - /// #![feature(const_option)] /// #![feature(const_nonnull_new)] + /// #![feature(const_option)] + /// #![feature(const_pointer_is_aligned)] /// use std::ptr::NonNull; /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1390,10 +1376,10 @@ impl NonNull { /// ``` /// /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 - #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - #[must_use] #[inline] + #[must_use] + #[stable(feature = "pointer_is_aligned", since = "1.79.0")] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned(self) -> bool where T: Sized, @@ -1505,10 +1491,10 @@ impl NonNull { /// ``` /// /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 + #[inline] + #[must_use] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - #[must_use] - #[inline] pub const fn is_aligned_to(self, align: usize) -> bool { self.pointer.is_aligned_to(align) } @@ -1578,11 +1564,8 @@ impl NonNull<[T]> { /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); /// assert!(!slice.is_empty()); /// ``` - #[stable(feature = "slice_ptr_is_empty_nonnull", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable( - feature = "const_slice_ptr_is_empty_nonnull", - since = "CURRENT_RUSTC_VERSION" - )] + #[stable(feature = "slice_ptr_is_empty_nonnull", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_ptr_is_empty_nonnull", since = "1.79.0")] #[must_use] #[inline] pub const fn is_empty(self) -> bool { diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 7910981d0f5ee..0b8ff5cc01242 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -70,21 +70,19 @@ macro_rules! iterator { $into_ref:ident, {$($extra:tt)*} ) => { - // Returns the first element and moves the start of the iterator forwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_unchecked { - ($self: ident) => { $self.post_inc_start(1).$into_ref() } - } - - // Returns the last element and moves the end of the iterator backwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_back_unchecked { - ($self: ident) => { $self.pre_dec_end(1).$into_ref() } - } - impl<'a, T> $name<'a, T> { + /// Returns the last element and moves the end of the iterator backwards by 1. + /// + /// # Safety + /// + /// The iterator must not be empty + #[inline] + unsafe fn next_back_unchecked(&mut self) -> $elem { + // SAFETY: the caller promised it's not empty, so + // the offsetting is in-bounds and there's an element to return. + unsafe { self.pre_dec_end(1).$into_ref() } + } + // Helper function for creating a slice from the iterator. #[inline(always)] fn make_slice(&self) -> &'a [T] { @@ -156,13 +154,13 @@ macro_rules! iterator { fn next(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - // SAFETY: The call to `next_unchecked!` is + // SAFETY: The call to `next_unchecked` is // safe since we check if the iterator is empty first. unsafe { if is_empty!(self) { None } else { - Some(next_unchecked!(self)) + Some(self.next_unchecked()) } } } @@ -191,7 +189,7 @@ macro_rules! iterator { // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { self.post_inc_start(n); - Some(next_unchecked!(self)) + Some(self.next_unchecked()) } } @@ -392,13 +390,13 @@ macro_rules! iterator { fn next_back(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - // SAFETY: The call to `next_back_unchecked!` + // SAFETY: The call to `next_back_unchecked` // is safe since we check if the iterator is empty first. unsafe { if is_empty!(self) { None } else { - Some(next_back_unchecked!(self)) + Some(self.next_back_unchecked()) } } } @@ -416,7 +414,7 @@ macro_rules! iterator { // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. unsafe { self.pre_dec_end(n); - Some(next_back_unchecked!(self)) + Some(self.next_back_unchecked()) } } @@ -436,10 +434,11 @@ macro_rules! iterator { unsafe impl TrustedLen for $name<'_, T> {} impl<'a, T> UncheckedIterator for $name<'a, T> { + #[inline] unsafe fn next_unchecked(&mut self) -> $elem { // SAFETY: The caller promised there's at least one more item. unsafe { - next_unchecked!(self) + self.post_inc_start(1).$into_ref() } } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6e1ba74f72b33..9c523fd6295d7 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1964,7 +1964,7 @@ impl [T] { /// assert_eq!(right, []); /// } /// ``` - #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] #[inline] #[must_use] @@ -2017,7 +2017,7 @@ impl [T] { /// } /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` - #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] #[inline] #[must_use] diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 59f873d1268ce..51a0777c2d613 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -6,6 +6,46 @@ use crate::iter::FusedIterator; use super::from_utf8_unchecked; use super::validations::utf8_char_width; +impl [u8] { + /// Creates an iterator over the contiguous valid UTF-8 ranges of this + /// slice, and the non-UTF-8 fragments in between. + /// + /// # Examples + /// + /// This function formats arbitrary but mostly-UTF-8 bytes into Rust source + /// code in the form of a C-string literal (`c"..."`). + /// + /// ``` + /// use std::fmt::Write as _; + /// + /// pub fn cstr_literal(bytes: &[u8]) -> String { + /// let mut repr = String::new(); + /// repr.push_str("c\""); + /// for chunk in bytes.utf8_chunks() { + /// for ch in chunk.valid().chars() { + /// // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for non-printable characters. + /// write!(repr, "{}", ch.escape_debug()).unwrap(); + /// } + /// for byte in chunk.invalid() { + /// write!(repr, "\\x{:02X}", byte).unwrap(); + /// } + /// } + /// repr.push('"'); + /// repr + /// } + /// + /// fn main() { + /// let lit = cstr_literal(b"\xferris the \xf0\x9f\xa6\x80\x07"); + /// let expected = stringify!(c"\xFErris the 🦀\u{7}"); + /// assert_eq!(lit, expected); + /// } + /// ``` + #[stable(feature = "utf8_chunks", since = "1.79.0")] + pub fn utf8_chunks(&self) -> Utf8Chunks<'_> { + Utf8Chunks { source: self } + } +} + /// An item returned by the [`Utf8Chunks`] iterator. /// /// A `Utf8Chunk` stores a sequence of [`u8`] up to the first broken character @@ -14,15 +54,11 @@ use super::validations::utf8_char_width; /// # Examples /// /// ``` -/// #![feature(utf8_chunks)] -/// -/// use std::str::Utf8Chunks; -/// /// // An invalid UTF-8 string /// let bytes = b"foo\xF1\x80bar"; /// /// // Decode the first `Utf8Chunk` -/// let chunk = Utf8Chunks::new(bytes).next().unwrap(); +/// let chunk = bytes.utf8_chunks().next().unwrap(); /// /// // The first three characters are valid UTF-8 /// assert_eq!("foo", chunk.valid()); @@ -30,7 +66,7 @@ use super::validations::utf8_char_width; /// // The fourth character is broken /// assert_eq!(b"\xF1\x80", chunk.invalid()); /// ``` -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] #[derive(Clone, Debug, PartialEq, Eq)] pub struct Utf8Chunk<'a> { valid: &'a str, @@ -43,7 +79,7 @@ impl<'a> Utf8Chunk<'a> { /// This substring can be empty at the start of the string or between /// broken UTF-8 characters. #[must_use] - #[unstable(feature = "utf8_chunks", issue = "99543")] + #[stable(feature = "utf8_chunks", since = "1.79.0")] pub fn valid(&self) -> &'a str { self.valid } @@ -63,7 +99,7 @@ impl<'a> Utf8Chunk<'a> { /// [`valid`]: Self::valid /// [`U+FFFD REPLACEMENT CHARACTER`]: crate::char::REPLACEMENT_CHARACTER #[must_use] - #[unstable(feature = "utf8_chunks", issue = "99543")] + #[stable(feature = "utf8_chunks", since = "1.79.0")] pub fn invalid(&self) -> &'a [u8] { self.invalid } @@ -78,7 +114,7 @@ impl fmt::Debug for Debug<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_char('"')?; - for chunk in Utf8Chunks::new(self.0) { + for chunk in self.0.utf8_chunks() { // Valid part. // Here we partially parse UTF-8 again which is suboptimal. { @@ -123,12 +159,8 @@ impl fmt::Debug for Debug<'_> { /// [`String::from_utf8_lossy`] without allocating heap memory: /// /// ``` -/// #![feature(utf8_chunks)] -/// -/// use std::str::Utf8Chunks; -/// /// fn from_utf8_lossy(input: &[u8], mut push: F) where F: FnMut(&str) { -/// for chunk in Utf8Chunks::new(input) { +/// for chunk in input.utf8_chunks() { /// push(chunk.valid()); /// /// if !chunk.invalid().is_empty() { @@ -140,19 +172,13 @@ impl fmt::Debug for Debug<'_> { /// /// [`String::from_utf8_lossy`]: ../../std/string/struct.String.html#method.from_utf8_lossy #[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] #[derive(Clone)] pub struct Utf8Chunks<'a> { source: &'a [u8], } impl<'a> Utf8Chunks<'a> { - /// Creates a new iterator to decode the bytes. - #[unstable(feature = "utf8_chunks", issue = "99543")] - pub fn new(bytes: &'a [u8]) -> Self { - Self { source: bytes } - } - #[doc(hidden)] #[unstable(feature = "str_internals", issue = "none")] pub fn debug(&self) -> Debug<'_> { @@ -160,7 +186,7 @@ impl<'a> Utf8Chunks<'a> { } } -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] impl<'a> Iterator for Utf8Chunks<'a> { type Item = Utf8Chunk<'a>; @@ -259,10 +285,10 @@ impl<'a> Iterator for Utf8Chunks<'a> { } } -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] impl FusedIterator for Utf8Chunks<'_> {} -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] impl fmt::Debug for Utf8Chunks<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish() diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 61a604561458b..adccbe02d46d4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -24,7 +24,7 @@ use crate::slice::{self, SliceIndex}; pub mod pattern; mod lossy; -#[unstable(feature = "utf8_chunks", issue = "99543")] +#[stable(feature = "utf8_chunks", since = "1.79.0")] pub use lossy::{Utf8Chunk, Utf8Chunks}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c8fd997a5da62..232ec589093d3 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -511,7 +511,7 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let mut some_bools = [const { AtomicBool::new(false) }; 10]; @@ -578,7 +578,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> bool { self.v.primitive_into_inner() != 0 } @@ -1313,7 +1313,7 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; /// @@ -1397,7 +1397,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> *mut T { self.p.primitive_into_inner() } @@ -2303,7 +2303,7 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// #[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")] @@ -2378,7 +2378,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable_access] - #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> $int_type { self.v.primitive_into_inner() } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index ff6b2d3053956..1aa6a288e7082 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -46,6 +46,8 @@ use crate::intrinsics::{self, const_eval_select}; /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough /// debuginfo to have a measurable compile-time impact on debug builds. #[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn +#[macro_export] +#[unstable(feature = "ub_checks", issue = "none")] macro_rules! assert_unsafe_precondition { ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => { { @@ -75,11 +77,13 @@ macro_rules! assert_unsafe_precondition { } }; } -pub(crate) use assert_unsafe_precondition; +#[unstable(feature = "ub_checks", issue = "none")] +pub use assert_unsafe_precondition; /// Checking library UB is always enabled when UB-checking is done /// (and we use a reexport so that there is no unnecessary wrapper function). -pub(crate) use intrinsics::ub_checks as check_library_ub; +#[unstable(feature = "ub_checks", issue = "none")] +pub use intrinsics::ub_checks as check_library_ub; /// Determines whether we should check for language UB. /// diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index eb1e1a0b9b1dd..8b731cf5b25d1 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -100,7 +100,6 @@ fn test_const_deallocate_at_runtime() { } } -#[cfg(not(bootstrap))] #[test] fn test_three_way_compare_in_const_contexts() { use core::cmp::Ordering::{self, *}; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e741149e7ce21..797108a8425de 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -21,7 +21,7 @@ #![feature(const_pointer_is_aligned)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_write)] -#![cfg_attr(not(bootstrap), feature(const_three_way_compare))] +#![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(const_likely)] #![feature(core_intrinsics)] @@ -42,12 +42,10 @@ #![feature(float_minimum_maximum)] #![feature(future_join)] #![feature(generic_assert_internals)] -#![feature(generic_nonzero)] #![feature(array_try_from_fn)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(try_find)] -#![feature(inline_const)] #![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] @@ -118,7 +116,6 @@ #![feature(error_generic_member_access)] #![feature(error_in_core)] #![feature(trait_upcasting)] -#![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] #![feature(iter_map_windows)] diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs index 9d3f0b65fdb94..6e70ea3e28574 100644 --- a/library/core/tests/str_lossy.rs +++ b/library/core/tests/str_lossy.rs @@ -1,10 +1,8 @@ -use core::str::Utf8Chunks; - #[test] fn chunks() { macro_rules! assert_chunks { ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{ - let mut iter = Utf8Chunks::new($string); + let mut iter = $string.utf8_chunks(); $( let chunk = iter.next().expect("missing chunk"); assert_eq!($valid, chunk.valid()); @@ -79,7 +77,7 @@ fn debug() { "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"", &format!( "{:?}", - Utf8Chunks::new(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa").debug(), + b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa".utf8_chunks().debug(), ), ); } diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index 48514e52587f0..331b66262490c 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -7,7 +7,6 @@ convert_float_to_int, core_intrinsics, decl_macro, - inline_const, intra_doc_pointers, repr_simd, simd_ffi, diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c8db028b651f6..23ae2e7dc0ded 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -26,7 +26,6 @@ #![feature(staged_api)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] -#![feature(generic_nonzero)] #![feature(maybe_uninit_write_slice)] #![feature(negative_impls)] #![feature(new_uninit)] @@ -1361,7 +1360,7 @@ impl Literal { } /// Byte character literal. - #[stable(feature = "proc_macro_byte_character", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_byte_character", since = "1.79.0")] pub fn byte_character(byte: u8) -> Literal { let string = [byte].escape_ascii().to_string(); Literal::new(bridge::LitKind::Byte, &string, None) @@ -1375,7 +1374,7 @@ impl Literal { } /// C string literal. - #[stable(feature = "proc_macro_c_str_literals", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_c_str_literals", since = "1.79.0")] pub fn c_string(string: &CStr) -> Literal { let string = string.to_bytes().escape_ascii().to_string(); Literal::new(bridge::LitKind::CStr, &string, None) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ce041404a2ecb..5ae1b3dfad597 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -532,6 +532,12 @@ impl OsString { let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; unsafe { Box::from_raw(rw) } } + + /// Part of a hack to make PathBuf::push/pop more efficient. + #[inline] + pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { + self.inner.as_mut_vec_for_path_buf() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index ff399a0acd5f3..dfa05671ab0f1 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1657,23 +1657,9 @@ fn test_file_times() { let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); times = times.set_accessed(accessed).set_modified(modified); - #[cfg(any( - windows, - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos", - ))] + #[cfg(any(windows, target_vendor = "apple"))] let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); - #[cfg(any( - windows, - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos", - ))] + #[cfg(any(windows, target_vendor = "apple"))] { times = times.set_created(created); } @@ -1698,27 +1684,14 @@ fn test_file_times() { let metadata = file.metadata().unwrap(); assert_eq!(metadata.accessed().unwrap(), accessed); assert_eq!(metadata.modified().unwrap(), modified); - #[cfg(any( - windows, - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos", - ))] + #[cfg(any(windows, target_vendor = "apple"))] { assert_eq!(metadata.created().unwrap(), created); } } #[test] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos" -))] +#[cfg(target_vendor = "apple")] fn test_file_times_pre_epoch_with_nanos() { #[cfg(target_os = "ios")] use crate::os::ios::fs::FileTimesExt; diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 5b782fff7e52e..f6680b211c7fa 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -95,7 +95,7 @@ impl Cursor { /// # force_inference(&buff); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn new(inner: T) -> Cursor { Cursor { pos: 0, inner } } @@ -132,7 +132,7 @@ impl Cursor { /// let reference = buff.get_ref(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn get_ref(&self) -> &T { &self.inner } @@ -178,7 +178,7 @@ impl Cursor { /// assert_eq!(buff.position(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn position(&self) -> u64 { self.pos } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 21ae7b91207c1..f366cb8f42baa 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -869,8 +869,6 @@ impl Error { /// # Examples /// /// ``` - /// #![feature(io_error_downcast)] - /// /// use std::fmt; /// use std::io; /// use std::error::Error; @@ -923,7 +921,7 @@ impl Error { /// assert!(io_error.raw_os_error().is_none()); /// # } /// ``` - #[unstable(feature = "io_error_downcast", issue = "99262")] + #[stable(feature = "io_error_downcast", since = "1.79.0")] pub fn downcast(self) -> result::Result where E: error::Error + Send + Sync + 'static, diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 266a447f06b5c..b4c4dffc371c1 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -51,7 +51,7 @@ pub struct Empty; /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn empty() -> Empty { Empty } @@ -173,7 +173,7 @@ pub struct Repeat { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn repeat(byte: u8) -> Repeat { Repeat { byte } } @@ -276,7 +276,7 @@ pub struct Sink; /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_io_structs", since = "1.79.0")] pub const fn sink() -> Sink { Sink } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 241a443fab96e..27b46b462044a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -224,7 +224,7 @@ `#![no_std]` or overriding this warning by enabling this feature." ) )] -#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] +#![rustc_preserve_ub_checks] #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", @@ -314,7 +314,6 @@ #![feature(thread_local)] #![feature(try_blocks)] #![feature(type_alias_impl_trait)] -#![feature(utf8_chunks)] // tidy-alphabetical-end // // Library features (core): @@ -335,7 +334,6 @@ #![feature(float_minimum_maximum)] #![feature(float_next_up_down)] #![feature(fmt_internals)] -#![feature(generic_nonzero)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_assert_unchecked)] @@ -358,6 +356,7 @@ #![feature(str_internals)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] +#![feature(ub_checks)] // tidy-alphabetical-end // // Library features (alloc): @@ -593,7 +592,6 @@ pub mod net; pub mod num; pub mod os; pub mod panic; -#[cfg(not(bootstrap))] #[unstable(feature = "core_pattern_types", issue = "none")] pub mod pat; pub mod path; diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 1343fdfd1dfdd..8910cdea7c0c9 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -23,11 +23,12 @@ pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError} )] pub use core::num::ZeroablePrimitive; -#[unstable(feature = "generic_nonzero", issue = "120257")] +#[stable(feature = "generic_nonzero", since = "1.79.0")] pub use core::num::NonZero; #[stable(feature = "signed_nonzero", since = "1.34.0")] pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 010ce4e5076ba..8c7fc4cb2e453 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -176,7 +176,12 @@ impl Drop for OwnedFd { // something like EINTR), we might close another valid file descriptor // opened after we closed ours. #[cfg(not(target_os = "hermit"))] - let _ = libc::close(self.fd); + { + #[cfg(unix)] + crate::sys::fs::debug_assert_fd_is_open(self.fd); + + let _ = libc::close(self.fd); + } #[cfg(target_os = "hermit")] let _ = hermit_abi::close(self.fd); } diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 16d9cd915acc1..3e45e3533ed28 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -17,14 +17,10 @@ mod tests; target_os = "linux", target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_vendor = "apple", ))] mod ucred; @@ -44,14 +40,10 @@ pub use self::stream::*; target_os = "linux", target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_vendor = "apple", ))] #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] pub use self::ucred::*; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 82b24dca1c41b..19fc7b3d8532f 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -3,14 +3,10 @@ target_os = "linux", target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", - target_os = "macos", - target_os = "watchos", - target_os = "visionos", target_os = "netbsd", target_os = "openbsd", - target_os = "nto" + target_os = "nto", + target_vendor = "apple", ))] use super::{peer_cred, UCred}; #[cfg(any(doc, target_os = "android", target_os = "linux"))] @@ -231,14 +227,10 @@ impl UnixStream { target_os = "linux", target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", - target_os = "macos", - target_os = "watchos", - target_os = "visionos", target_os = "netbsd", target_os = "openbsd", - target_os = "nto" + target_os = "nto", + target_vendor = "apple", ))] pub fn peer_cred(&self) -> io::Result { peer_cred(self) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index 3a752a53a5062..1497e730bbf15 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -35,14 +35,8 @@ pub(super) use self::impl_linux::peer_cred; ))] pub(super) use self::impl_bsd::peer_cred; -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos" -))] -pub(super) use self::impl_mac::peer_cred; +#[cfg(target_vendor = "apple")] +pub(super) use self::impl_apple::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] mod impl_linux { @@ -103,14 +97,8 @@ mod impl_bsd { } } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos" -))] -mod impl_mac { +#[cfg(target_vendor = "apple")] +mod impl_apple { use super::UCred; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; diff --git a/library/std/src/os/unix/net/ucred/tests.rs b/library/std/src/os/unix/net/ucred/tests.rs index 2a0797877c6fc..a6cc81318fc08 100644 --- a/library/std/src/os/unix/net/ucred/tests.rs +++ b/library/std/src/os/unix/net/ucred/tests.rs @@ -7,12 +7,8 @@ use libc::{getegid, geteuid, getpid}; target_os = "linux", target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", - target_os = "macos", - target_os = "watchos", - target_os = "visionos", - target_os = "openbsd" + target_os = "openbsd", + target_vendor = "apple", ))] fn test_socket_pair() { // Create two connected sockets and get their peer credentials. They should be equal. @@ -28,14 +24,7 @@ fn test_socket_pair() { } #[test] -#[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos", -))] +#[cfg(any(target_os = "linux", target_vendor = "apple"))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0636f55771eed..79d800ff0729b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1158,12 +1158,6 @@ impl FusedIterator for Ancestors<'_> {} /// Which method works best depends on what kind of situation you're in. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] -// `PathBuf::as_mut_vec` current implementation relies -// on `PathBuf` being layout-compatible with `Vec`. -// However, `PathBuf` layout is considered an implementation detail and must not be relied upon. We -// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under -// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. -#[cfg_attr(not(doc), repr(transparent))] pub struct PathBuf { inner: OsString, } @@ -1171,7 +1165,7 @@ pub struct PathBuf { impl PathBuf { #[inline] fn as_mut_vec(&mut self) -> &mut Vec { - unsafe { &mut *(self as *mut PathBuf as *mut Vec) } + self.inner.as_mut_vec_for_path_buf() } /// Allocates an empty `PathBuf`. @@ -3332,7 +3326,6 @@ impl Error for StripPrefixError { /// ## Posix paths /// /// ``` -/// #![feature(absolute_path)] /// # #[cfg(unix)] /// fn main() -> std::io::Result<()> { /// use std::path::{self, Path}; @@ -3357,7 +3350,6 @@ impl Error for StripPrefixError { /// ## Windows paths /// /// ``` -/// #![feature(absolute_path)] /// # #[cfg(windows)] /// fn main() -> std::io::Result<()> { /// use std::path::{self, Path}; @@ -3382,7 +3374,7 @@ impl Error for StripPrefixError { /// /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew -#[unstable(feature = "absolute_path", issue = "92750")] +#[stable(feature = "absolute_path", since = "1.79.0")] pub fn absolute>(path: P) -> io::Result { let path = path.as_ref(); if path.as_os_str().is_empty() { diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index f61e04e02b666..01936734d7548 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -84,7 +84,6 @@ pub use core::prelude::v1::cfg_eval; )] pub use core::prelude::v1::type_ascribe; -#[cfg(not(bootstrap))] // Do not `doc(no_inline)` either. #[unstable( feature = "deref_patterns", diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 69cc61b30efe9..4a73a9be88bc1 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1865,7 +1865,8 @@ impl ExitStatusError { /// # Examples /// /// ``` - /// #![feature(exit_status_error, generic_nonzero)] + /// #![feature(exit_status_error)] + /// /// # if cfg!(unix) { /// use std::num::NonZero; /// use std::process::Command; diff --git a/library/std/src/sync/reentrant_lock/tests.rs b/library/std/src/sync/reentrant_lock/tests.rs index d4c1d440c6109..aeef0289d28f8 100644 --- a/library/std/src/sync/reentrant_lock/tests.rs +++ b/library/std/src/sync/reentrant_lock/tests.rs @@ -1,4 +1,4 @@ -use super::{ReentrantLock, ReentrantLockGuard}; +use super::ReentrantLock; use crate::cell::RefCell; use crate::sync::Arc; use crate::thread; @@ -51,10 +51,3 @@ fn trylock_works() { .unwrap(); let _lock3 = l.try_lock(); } - -pub struct Answer<'a>(pub ReentrantLockGuard<'a, RefCell>); -impl Drop for Answer<'_> { - fn drop(&mut self) { - *self.0.borrow_mut() = 42; - } -} diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 4ca3f1cd1853a..18b969bca85a6 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -11,8 +11,6 @@ use crate::str; use crate::sync::Arc; use crate::sys_common::{AsInner, IntoInner}; -use core::str::Utf8Chunks; - #[cfg(test)] mod tests; @@ -29,7 +27,7 @@ pub struct Slice { impl fmt::Debug for Slice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&Utf8Chunks::new(&self.inner).debug(), f) + fmt::Debug::fmt(&self.inner.utf8_chunks().debug(), f) } } @@ -41,7 +39,7 @@ impl fmt::Display for Slice { return "".fmt(f); } - for chunk in Utf8Chunks::new(&self.inner) { + for chunk in self.inner.utf8_chunks() { let valid = chunk.valid(); // If we successfully decoded the whole chunk as a valid string then // we can return a direct formatting of the string which will also @@ -198,6 +196,12 @@ impl Buf { pub fn into_rc(&self) -> Rc { self.as_slice().into_rc() } + + /// Part of a hack to make PathBuf::push/pop more efficient. + #[inline] + pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { + &mut self.inner + } } impl Slice { diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 352bd7359033a..b3ceb55802dc5 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -158,6 +158,12 @@ impl Buf { pub fn into_rc(&self) -> Rc { self.as_slice().into_rc() } + + /// Part of a hack to make PathBuf::push/pop more efficient. + #[inline] + pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { + self.inner.as_mut_vec_for_path_buf() + } } impl Slice { diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index acf8100d47f23..2a3298e8b4c9d 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -98,12 +98,10 @@ mod imp { } #[inline(always)] - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize - // `ARGC` and `ARGV`. But in Miri that does not actually happen so we - // still initialize here. - #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))] - really_init(_argc, _argv); + pub unsafe fn init(argc: isize, argv: *const *const u8) { + // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" + // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. + really_init(argc, argv); } /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. @@ -170,13 +168,7 @@ mod imp { } } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" -))] +#[cfg(target_vendor = "apple")] mod imp { use super::Args; use crate::ffi::CStr; @@ -217,12 +209,7 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(any( - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos" - ))] + #[cfg(not(target_os = "macos"))] pub fn args() -> Args { use crate::ffi::{c_char, c_void, OsString}; use crate::mem; diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 3456155509ef3..d2006dfc12b55 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -20,14 +20,7 @@ use crate::sys::time::SystemTime; use crate::sys::{cvt, cvt_r}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -#[cfg(any( - all(target_os = "linux", target_env = "gnu"), - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", -))] +#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] use crate::sys::weak::syscall; #[cfg(any(target_os = "android", target_os = "macos", target_os = "solaris"))] use crate::sys::weak::weak; @@ -35,13 +28,9 @@ use crate::sys::weak::weak; use libc::{c_int, mode_t}; #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "solaris", - all(target_os = "linux", target_env = "gnu") + all(target_os = "linux", target_env = "gnu"), + target_vendor = "apple", ))] use libc::c_char; #[cfg(any( @@ -198,20 +187,16 @@ cfg_has_statx! {{ return Some(Err(err)); } - // `ENOSYS` might come from a faulty FUSE driver. - // - // Other errors are not a good enough indicator either -- it is - // known that `EPERM` can be returned as a result of using seccomp to - // block the syscall. + // We're not yet entirely sure whether `statx` is usable on this kernel + // or not. Syscalls can return errors from things other than the kernel + // per se, e.g. `EPERM` can be returned if seccomp is used to block the + // syscall, or `ENOSYS` might be returned from a faulty FUSE driver. // // Availability is checked by performing a call which expects `EFAULT` // if the syscall is usable. // // See: https://github.com/rust-lang/rust/issues/65662 // - // FIXME this can probably just do the call if `EPERM` was received, but - // previous iteration of the code checked it for all errors and for now - // this is retained. // FIXME what about transient conditions like `ENOMEM`? let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut())) .err() @@ -379,13 +364,7 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option, modified: Option, - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" - ))] + #[cfg(target_vendor = "apple")] created: Option, } @@ -558,15 +537,7 @@ impl FileAttr { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } - #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - ))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_vendor = "apple"))] pub fn created(&self) -> io::Result { SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64) } @@ -574,12 +545,8 @@ impl FileAttr { #[cfg(not(any( target_os = "freebsd", target_os = "openbsd", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "vita", + target_vendor = "apple", )))] pub fn created(&self) -> io::Result { cfg_has_statx! { @@ -659,13 +626,7 @@ impl FileTimes { self.modified = Some(t); } - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" - ))] + #[cfg(target_vendor = "apple")] pub fn set_created(&mut self, t: SystemTime) { self.created = Some(t); } @@ -868,8 +829,42 @@ impl Iterator for ReadDir { } } +/// Aborts the process if a file desceriptor is not open, if debug asserts are enabled +/// +/// Many IO syscalls can't be fully trusted about EBADF error codes because those +/// might get bubbled up from a remote FUSE server rather than the file descriptor +/// in the current process being invalid. +/// +/// So we check file flags instead which live on the file descriptor and not the underlying file. +/// The downside is that it costs an extra syscall, so we only do it for debug. +#[inline] +pub(crate) fn debug_assert_fd_is_open(fd: RawFd) { + use crate::sys::os::errno; + + // this is similar to assert_unsafe_precondition!() but it doesn't require const + if core::ub_checks::check_library_ub() { + if unsafe { libc::fcntl(fd, libc::F_GETFD) } == -1 && errno() == libc::EBADF { + rtabort!("IO Safety violation: owned file descriptor already closed"); + } + } +} + impl Drop for Dir { fn drop(&mut self) { + // dirfd isn't supported everywhere + #[cfg(not(any( + miri, + target_os = "redox", + target_os = "nto", + target_os = "vita", + target_os = "hurd", + target_os = "espidf", + target_os = "fuchsia", + )))] + { + let fd = unsafe { libc::dirfd(self.0) }; + debug_assert_fd_is_open(fd); + } let r = unsafe { libc::closedir(self.0) }; assert!( r == 0 || crate::io::Error::last_os_error().is_interrupted(), @@ -966,11 +961,6 @@ impl DirEntry { } #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "linux", target_os = "emscripten", target_os = "android", @@ -987,6 +977,7 @@ impl DirEntry { target_os = "aix", target_os = "nto", target_os = "hurd", + target_vendor = "apple", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -1003,15 +994,11 @@ impl DirEntry { } #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", - target_os = "dragonfly" + target_os = "dragonfly", + target_vendor = "apple", ))] fn name_bytes(&self) -> &[u8] { use crate::slice; @@ -1023,15 +1010,11 @@ impl DirEntry { } } #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", - target_os = "dragonfly" + target_os = "dragonfly", + target_vendor = "apple", )))] fn name_bytes(&self) -> &[u8] { self.name_cstr().to_bytes() @@ -1209,23 +1192,11 @@ impl File { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - ))] + #[cfg(target_vendor = "apple")] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - )))] + #[cfg(not(target_vendor = "apple"))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -1235,13 +1206,7 @@ impl File { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - ))] + #[cfg(target_vendor = "apple")] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } @@ -1260,16 +1225,12 @@ impl File { #[cfg(not(any( target_os = "android", target_os = "freebsd", - target_os = "ios", - target_os = "tvos", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "watchos", - target_os = "visionos", target_os = "nto", target_os = "hurd", + target_vendor = "apple", )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1378,7 +1339,7 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] { + } else if #[cfg(target_vendor = "apple")] { let mut buf = [mem::MaybeUninit::::uninit(); 3]; let mut num_times = 0; let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; @@ -1910,15 +1871,7 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", -)))] +#[cfg(not(any(target_os = "linux", target_os = "android", target_vendor = "apple")))] pub fn copy(from: &Path, to: &Path) -> io::Result { let (mut reader, reader_metadata) = open_from(from)?; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; @@ -1944,13 +1897,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" -))] +#[cfg(target_vendor = "apple")] pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 3ef43a923a377..01d7fb31d7d6c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -78,16 +78,12 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "emscripten", target_os = "fuchsia", target_os = "vxworks", - // The poll on Darwin doesn't set POLLNVAL for closed fds. - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "redox", target_os = "l4re", target_os = "horizon", target_os = "vita", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_vendor = "apple", )))] 'poll: { use crate::sys::os::errno; @@ -406,7 +402,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] extern "C" {} - } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] { + } else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Foundation", kind = "framework")] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 96492fedece78..3a281525f8df3 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -63,17 +63,7 @@ extern "C" { )] #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] - #[cfg_attr( - any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "freebsd", - target_os = "watchos", - target_os = "visionos", - ), - link_name = "__error" - )] + #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] #[cfg_attr(target_os = "aix", link_name = "_Errno")] fn errno_location() -> *mut c_int; @@ -431,13 +421,7 @@ pub fn current_exe() -> io::Result { Ok(PathBuf::from(OsString::from_vec(e))) } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" -))] +#[cfg(target_vendor = "apple")] pub fn current_exe() -> io::Result { unsafe { let mut sz: u32 = 0; @@ -703,32 +687,26 @@ pub fn home_dir() -> Option { #[cfg(any( target_os = "android", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita", + all(target_vendor = "apple", not(target_os = "macos")), ))] unsafe fn fallback() -> Option { None } #[cfg(not(any( target_os = "android", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita", + all(target_vendor = "apple", not(target_os = "macos")), )))] unsafe fn fallback() -> Option { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index d65657790c48b..f2947161cd56d 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -420,13 +420,11 @@ impl Command { } #[cfg(not(any( - target_os = "macos", - target_os = "tvos", - target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), target_os = "nto", + target_vendor = "apple", )))] fn posix_spawn( &mut self, @@ -439,14 +437,11 @@ impl Command { // Only support platforms for which posix_spawn() can return ENOENT // directly. #[cfg(any( - target_os = "macos", - // FIXME: `target_os = "ios"`? - target_os = "tvos", - target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), target_os = "nto", + target_vendor = "apple", ))] fn posix_spawn( &mut self, @@ -530,7 +525,7 @@ impl Command { } let addchdir = match self.get_cwd() { Some(cwd) => { - if cfg!(any(target_os = "macos", target_os = "tvos", target_os = "watchos")) { + if cfg!(target_vendor = "apple") { // There is a bug in macOS where a relative executable // path like "../myprogram" will cause `posix_spawn` to // successfully launch the program, but erroneously return @@ -1040,24 +1035,20 @@ fn signal_string(signal: i32) -> &'static str { #[cfg(any(target_os = "linux", target_os = "nto"))] libc::SIGPWR => " (SIGPWR)", #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "nto", + target_vendor = "apple", ))] libc::SIGEMT => " (SIGEMT)", #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", - target_os = "dragonfly" + target_os = "dragonfly", + target_vendor = "apple", ))] libc::SIGINFO => " (SIGINFO)", #[cfg(target_os = "hurd")] diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs index de087d98eb8ba..d8f227b4ef444 100644 --- a/library/std/src/sys/pal/unix/rand.rs +++ b/library/std/src/sys/pal/unix/rand.rs @@ -12,11 +12,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(all( unix, - not(target_os = "macos"), - not(target_os = "ios"), - not(target_os = "tvos"), - not(target_os = "watchos"), - not(target_os = "visionos"), not(target_os = "openbsd"), not(target_os = "netbsd"), not(target_os = "fuchsia"), @@ -24,6 +19,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { not(target_os = "vxworks"), not(target_os = "emscripten"), not(target_os = "vita"), + not(target_vendor = "apple"), ))] mod imp { use crate::fs::File; diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 6a6bfc77a8541..853ef8736de24 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -150,13 +150,7 @@ impl Thread { } } - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" - ))] + #[cfg(target_vendor = "apple")] pub fn set_name(name: &CStr) { unsafe { let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); @@ -301,14 +295,10 @@ impl Drop for Thread { #[cfg(any( target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "nto", target_os = "solaris", target_os = "illumos", + target_vendor = "apple", ))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; @@ -325,11 +315,9 @@ pub fn available_parallelism() -> io::Result> { target_os = "emscripten", target_os = "fuchsia", target_os = "hurd", - target_os = "ios", - target_os = "tvos", target_os = "linux", - target_os = "macos", target_os = "aix", + target_vendor = "apple", ))] { #[allow(unused_assignments)] #[allow(unused_mut)] diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs index 1164c1782f4b7..75db6e112ed35 100644 --- a/library/std/src/sys/pal/unix/thread_local_dtor.rs +++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs @@ -76,13 +76,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { // workaround below is to register, via _tlv_atexit, a custom DTOR list once per // thread. thread_local dtors are pushed to the DTOR list without calling // _tlv_atexit. -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" -))] +#[cfg(target_vendor = "apple")] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::cell::{Cell, RefCell}; use crate::ptr; diff --git a/library/std/src/sys/pal/unix/thread_parking/mod.rs b/library/std/src/sys/pal/unix/thread_parking/mod.rs index 3348d4b366d22..c7fa39f07b640 100644 --- a/library/std/src/sys/pal/unix/thread_parking/mod.rs +++ b/library/std/src/sys/pal/unix/thread_parking/mod.rs @@ -11,16 +11,7 @@ )))] cfg_if::cfg_if! { - if #[cfg(all( - any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos", - ), - not(miri), - ))] { + if #[cfg(all(target_vendor = "apple", not(miri)))] { mod darwin; pub use darwin::Parker; } else if #[cfg(target_os = "netbsd")] { diff --git a/library/std/src/sys/pal/unix/thread_parking/pthread.rs b/library/std/src/sys/pal/unix/thread_parking/pthread.rs index d0ad3e2ce3ee4..8e295453d7675 100644 --- a/library/std/src/sys/pal/unix/thread_parking/pthread.rs +++ b/library/std/src/sys/pal/unix/thread_parking/pthread.rs @@ -43,15 +43,7 @@ unsafe fn wait_timeout( ) { // Use the system clock on systems that do not support pthread_condattr_setclock. // This unfortunately results in problems when the system time changes. - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - target_os = "espidf", - target_os = "horizon", - ))] + #[cfg(any(target_os = "espidf", target_os = "horizon", target_vendor = "apple"))] let (now, dur) = { use crate::cmp::min; use crate::sys::time::SystemTime; @@ -72,15 +64,7 @@ unsafe fn wait_timeout( (now, dur) }; // Use the monotonic clock on other systems. - #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - target_os = "espidf", - target_os = "horizon", - )))] + #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_vendor = "apple")))] let (now, dur) = { use crate::sys::time::Timespec; @@ -122,15 +106,11 @@ impl Parker { cfg_if::cfg_if! { if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "l4re", target_os = "android", target_os = "redox", target_os = "vita", + target_vendor = "apple", ))] { addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index e69775be8cf8e..535fe6b27d91e 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -86,13 +86,7 @@ impl Timespec { // Please note that Apple OS nonetheless accepts the standard unix format when // setting file times, which makes this compensation round-trippable and generally // transparent. - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", - ))] + #[cfg(target_vendor = "apple")] let (tv_sec, tv_nsec) = if (tv_sec <= 0 && tv_sec > i64::MIN) && (tv_nsec < 0 && tv_nsec > -1_000_000_000) { (tv_sec - 1, tv_nsec + 1_000_000_000) @@ -275,21 +269,9 @@ impl Instant { // // Instant on macos was historically implemented using mach_absolute_time; // we preserve this value domain out of an abundance of caution. - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" - ))] + #[cfg(target_vendor = "apple")] const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; - #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "visionos", - target_os = "tvos" - )))] + #[cfg(not(target_vendor = "apple"))] const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; Instant { t: Timespec::now(clock_id) } } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index b49585599cb32..ff41f6e77be7a 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -201,14 +201,21 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { // currently reside in the buffer. This function is an abstraction over these // functions by making them easier to call. // -// The first callback, `f1`, is yielded a (pointer, len) pair which can be +// The first callback, `f1`, is passed a (pointer, len) pair which can be // passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). -// The closure is expected to return what the syscall returns which will be -// interpreted by this function to determine if the syscall needs to be invoked -// again (with more buffer space). +// The closure is expected to: +// - On success, return the actual length of the written data *without* the null terminator. +// This can be 0. In this case the last_error must be left unchanged. +// - On insufficient buffer space, +// - either return the required length *with* the null terminator, +// - or set the last-error to ERROR_INSUFFICIENT_BUFFER and return `len`. +// - On other failure, return 0 and set last_error. +// +// This is how most but not all syscalls indicate the required buffer space. +// Other syscalls may need translation to match this protocol. // // Once the syscall has completed (errors bail out early) the second closure is -// yielded the data which has been read from the syscall. The return value +// passed the data which has been read from the syscall. The return value // from this closure is then the return value of the function. pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result where diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 374c9845ea4bb..64d8b72aed282 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -326,6 +326,8 @@ fn home_dir_crt() -> Option { super::fill_utf16_buf( |buf, mut sz| { + // GetUserProfileDirectoryW does not quite use the usual protocol for + // negotiating the buffer size, so we have to translate. match c::GetUserProfileDirectoryW( ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, diff --git a/library/std/src/sys/pal/windows/thread_local_key.rs b/library/std/src/sys/pal/windows/thread_local_key.rs index 4c00860dae389..e5ba619fc6ba4 100644 --- a/library/std/src/sys/pal/windows/thread_local_key.rs +++ b/library/std/src/sys/pal/windows/thread_local_key.rs @@ -141,9 +141,15 @@ impl StaticKey { panic!("out of TLS indexes"); } - self.key.store(key + 1, Release); register_dtor(self); + // Release-storing the key needs to be the last thing we do. + // This is because in `fn key()`, other threads will do an acquire load of the key, + // and if that sees this write then it will entirely bypass the `InitOnce`. We thus + // need to establish synchronization through `key`. In particular that acquire load + // must happen-after the register_dtor above, to ensure the dtor actually runs! + self.key.store(key + 1, Release); + let r = c::InitOnceComplete(self.once.get(), 0, ptr::null_mut()); debug_assert_eq!(r, c::TRUE); @@ -313,8 +319,22 @@ unsafe fn run_dtors() { // Use acquire ordering to observe key initialization. let mut cur = DTORS.load(Acquire); while !cur.is_null() { - let key = (*cur).key.load(Relaxed) - 1; + let pre_key = (*cur).key.load(Acquire); let dtor = (*cur).dtor.unwrap(); + cur = (*cur).next.load(Relaxed); + + // In StaticKey::init, we register the dtor before setting `key`. + // So if one thread's `run_dtors` races with another thread executing `init` on the same + // `StaticKey`, we can encounter a key of 0 here. That means this key was never + // initialized in this thread so we can safely skip it. + if pre_key == 0 { + continue; + } + // If this is non-zero, then via the `Acquire` load above we synchronized with + // everything relevant for this key. (It's not clear that this is needed, since the + // release-acquire pair on DTORS also establishes synchronization, but better safe than + // sorry.) + let key = pre_key - 1; let ptr = c::TlsGetValue(key); if !ptr.is_null() { @@ -322,8 +342,6 @@ unsafe fn run_dtors() { dtor(ptr as *mut _); any_run = true; } - - cur = (*cur).next.load(Relaxed); } if !any_run { diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 0475f9850786f..a2a96410d932c 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -30,14 +30,10 @@ impl LazyInit for AllocatedCondvar { cfg_if::cfg_if! { if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "l4re", target_os = "android", - target_os = "redox" + target_os = "redox", + target_vendor = "apple", ))] { // `pthread_condattr_setclock` is unfortunately not supported on these platforms. } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { @@ -124,14 +120,10 @@ impl Condvar { // default system clock). This approach avoids all problems that result // from changes made to the system time. #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "android", target_os = "espidf", - target_os = "horizon" + target_os = "horizon", + target_vendor = "apple", )))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::Timespec; @@ -160,14 +152,10 @@ impl Condvar { // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", target_os = "android", target_os = "espidf", - target_os = "horizon" + target_os = "horizon", + target_vendor = "apple", ))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::SystemTime; diff --git a/library/std/src/sys/thread_local/fast_local.rs b/library/std/src/sys/thread_local/fast_local.rs index 69ee70de30c02..49b51a729e428 100644 --- a/library/std/src/sys/thread_local/fast_local.rs +++ b/library/std/src/sys/thread_local/fast_local.rs @@ -1,7 +1,7 @@ use super::lazy::LazyKeyInner; use crate::cell::Cell; use crate::sys::thread_local_dtor::register_dtor; -use crate::{fmt, mem, panic}; +use crate::{fmt, mem, panic, ptr}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)] @@ -237,8 +237,9 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) { // Wrap the call in a catch to ensure unwinding is caught in the event // a panic takes place in a destructor. if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { - let value = (*ptr).inner.take(); - (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + let Key { inner, dtor_state } = &*ptr; + let value = inner.take(); + dtor_state.set(DtorState::RunningOrHasRun); drop(value); })) { rtabort!("thread local panicked on drop"); diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 8b2c839f837d4..7500c95d8b473 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -91,13 +91,15 @@ mod lazy { } } - /// The other methods hand out references while taking &self. - /// As such, callers of this method must ensure no `&` and `&mut` are - /// available and used at the same time. + /// Watch out: unsynchronized internal mutability! + /// + /// # Safety + /// Causes UB if any reference to the value is used after this. #[allow(unused)] - pub unsafe fn take(&mut self) -> Option { - // SAFETY: See doc comment for this method. - unsafe { (*self.inner.get()).take() } + pub(crate) unsafe fn take(&self) -> Option { + let mutable: *mut _ = UnsafeCell::get(&self.inner); + // SAFETY: That's the caller's problem. + unsafe { mutable.replace(None) } } } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 6a268633f72c1..95ca67fc2e0b6 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -17,10 +17,17 @@ use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( - target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "visionos", - target_os = "openbsd", target_os = "netbsd", target_os = "illumos", - target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku", + target_os = "l4re", + target_os = "nto", + target_vendor = "apple", + ))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; } else { diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 2dbd19d717199..38e15f9f54960 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -468,6 +468,12 @@ impl Wtf8Buf { let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } } + + /// Part of a hack to make PathBuf::push/pop more efficient. + #[inline] + pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { + &mut self.bytes + } } /// Creates a new WTF-8 string from an iterator of code points. diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 494513f2c75ce..1fb1333be0e45 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -40,11 +40,7 @@ fn test_named_thread() { #[cfg(any( // Note: musl didn't add pthread_getname_np until 1.2.3 all(target_os = "linux", target_env = "gnu"), - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "visionos", + target_vendor = "apple", ))] #[test] fn test_named_thread_truncation() { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index f3c22061d25de..f3a26e2593831 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -17,7 +17,6 @@ #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] #![doc(rust_logo)] -#![feature(generic_nonzero)] #![feature(rustdoc_internals)] #![feature(internal_output_capture)] #![feature(staged_api)] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 39add60e705fe..e464e444fea20 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1035,14 +1035,8 @@ def check_vendored_status(self): if self.use_vendored_sources: vendor_dir = os.path.join(self.rust_root, 'vendor') if not os.path.exists(vendor_dir): - sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \ - "--sync ./src/tools/rust-analyzer/Cargo.toml " \ - "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \ - "--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \ - "--sync ./src/bootstrap/Cargo.toml " eprint('ERROR: vendoring required, but vendor directory does not exist.') - eprint(' Run `cargo vendor {}` to initialize the ' - 'vendor directory.'.format(sync_dirs)) + eprint(' Run `x.py vendor` to initialize the vendor directory.') eprint(' Alternatively, use the pre-vendored `rustc-src` dist component.') eprint(' To get a stable/beta/nightly version, download it from: ') eprint(' ' diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index d6e60d52d6329..fc433bc5843b5 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -53,15 +53,12 @@ check-aux: src/tools/cargotest \ $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. - # We use a 64bit little-endian and a 32bit big-endian target for max coverage. $(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \ $(BOOTSTRAP) miri --stage 2 \ - --target x86_64-unknown-linux-gnu,mips-unknown-linux-gnu \ library/core \ library/alloc \ --no-doc # Some doctests have intentional memory leaks. - # Also, they work only on the host. $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ @@ -76,10 +73,11 @@ check-aux: $(BOOTSTRAP) miri --stage 2 library/std \ --doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: - # Also test some very target-specific modules on other targets. + # Also test some very target-specific modules on other targets + # (making sure to cover an i686 target as well). $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ $(BOOTSTRAP) miri --stage 2 library/std \ - --target aarch64-apple-darwin,i686-pc-windows-gnu \ + --target aarch64-apple-darwin,i686-pc-windows-msvc \ --no-doc -- \ time:: sync:: thread:: env:: dist: diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 5bcaeed7faa13..a81d640301363 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -1,4 +1,4 @@ -//! Implementation of `make clean` in rustbuild. +//! `./x.py clean` //! //! Responsible for cleaning out a build directory of all old and stale //! artifacts to prepare for a fresh build. Currently doesn't remove the diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c20653b5dfa6a..1d46a158f9ed2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -43,7 +43,7 @@ pub struct Std { /// This shouldn't be used from other steps; see the comment on [`Rustc`]. crates: Vec, /// When using download-rustc, we need to use a new build of `std` for running unit tests of Std itself, - /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overriden by `builder.ensure` from other steps. + /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overridden by `builder.ensure` from other steps. force_recompile: bool, extra_rust_args: &'static [&'static str], is_for_mir_opt_tests: bool, diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0eca20901b762..5bc9d7615e2bc 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -25,7 +25,7 @@ use crate::core::build_steps::llvm; use crate::core::build_steps::tool::{self, Tool}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; -use crate::utils::channel; +use crate::utils::channel::{self, Info}; use crate::utils::helpers::{exe, is_dylib, output, t, target_supports_cranelift_backend, timeit}; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; @@ -830,6 +830,12 @@ fn copy_src_dirs( return false; } + // Cargo tests use some files like `.gitignore` that we would otherwise exclude. + const CARGO_TESTS: &[&str] = &["tools/cargo/tests", "tools\\cargo\\tests"]; + if CARGO_TESTS.iter().any(|path| spath.contains(path)) { + return true; + } + let full_path = Path::new(dir).join(path); if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) { return false; @@ -985,10 +991,17 @@ impl Step for PlainSourceTarball { // Create the version file builder.create(&plain_dst_src.join("version"), &builder.rust_version()); - if let Some(info) = builder.rust_info().info() { - channel::write_commit_hash_file(plain_dst_src, &info.sha); - channel::write_commit_info_file(plain_dst_src, info); - } + + // Create the files containing git info, to ensure --version outputs the same. + let write_git_info = |info: Option<&Info>, path: &Path| { + if let Some(info) = info { + t!(std::fs::create_dir_all(path)); + channel::write_commit_hash_file(path, &info.sha); + channel::write_commit_info_file(path, info); + } + }; + write_git_info(builder.rust_info().info(), plain_dst_src); + write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo")); // If we're building from git or tarball sources, we need to vendor // a complete distribution. diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index 9b7378165de41..381ee7ef53b4c 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -14,3 +14,4 @@ pub(crate) mod synthetic_targets; pub(crate) mod test; pub(crate) mod tool; pub(crate) mod toolstate; +pub(crate) mod vendor; diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 7028bffea5442..354eb2b600381 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -1,3 +1,8 @@ +//! Build-and-run steps for in-repo tools +//! +//! A bit of a hodge-podge as e.g. if a tool's a test fixture it should be in `build_steps::test`. +//! If it can be reached from `./x.py run` it can go here. + use std::path::PathBuf; use std::process::Command; @@ -10,32 +15,6 @@ use crate::core::config::TargetSelection; use crate::utils::helpers::output; use crate::Mode; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExpandYamlAnchors; - -impl Step for ExpandYamlAnchors { - type Output = (); - - /// Runs the `expand-yaml_anchors` tool. - /// - /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the - /// anchors in them, since GitHub Actions doesn't support them. - fn run(self, builder: &Builder<'_>) { - builder.info("Expanding YAML anchors in the GitHub Actions configuration"); - builder.run_delaying_failure( - builder.tool_cmd(Tool::ExpandYamlAnchors).arg("generate").arg(&builder.src), - ); - } - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/expand-yaml-anchors") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(ExpandYamlAnchors); - } -} - #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct BuildManifest; diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index c0683cdda1e54..df38d6166eb85 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -1,3 +1,10 @@ +//! First time setup of a dev environment +//! +//! These are build-and-run steps for `./x.py setup`, which allows quickly setting up the directory +//! for modifying, building, and running the compiler and library. Running arbitrary configuration +//! allows setting up things that cannot be simply captured inside the config.toml, in addition to +//! leading people away from manually editing most of the config.toml values. + use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; @@ -25,6 +32,8 @@ pub enum Profile { None, } +static PROFILE_DIR: &str = "src/bootstrap/defaults"; + /// A list of historical hashes of `src/etc/rust_analyzer_settings.json`. /// New entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. @@ -41,7 +50,7 @@ static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyze impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { - PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self)) + PathBuf::from(format!("{}/{PROFILE_DIR}/config.{}.toml", src_path.display(), self)) } pub fn all() -> impl Iterator { @@ -220,7 +229,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id; let settings = format!( - "# Includes one of the default files in src/bootstrap/defaults\n\ + "# Includes one of the default files in {PROFILE_DIR}\n\ profile = \"{profile}\"\n\ change-id = {latest_change_id}\n" ); diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index c057fa9a5667b..754d1e61da8c6 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -1,3 +1,5 @@ +//! Attempt to magically identify good tests to run + #![cfg_attr(feature = "build-metrics", allow(unused))] use clap::Parser; diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ca10a128b9814..9a585a39e1eeb 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1,7 +1,7 @@ -//! Implementation of the test-related targets of the build system. +//! Build-and-run steps for `./x.py test` test fixtures //! -//! This file implements the various regression test suites that we execute on -//! our CI. +//! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules. +//! However, this contains ~all test parts we expect people to be able to build and run locally. use std::env; use std::ffi::OsStr; @@ -1146,8 +1146,6 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to builder.info("tidy check"); builder.run_delaying_failure(&mut cmd); - builder.ensure(ExpandYamlAnchors); - builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] .map(|filename| builder.src.join("src/etc/completions").join(filename)); @@ -1175,39 +1173,6 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExpandYamlAnchors; - -impl Step for ExpandYamlAnchors { - type Output = (); - const ONLY_HOSTS: bool = true; - - /// Ensure the `generate-ci-config` tool was run locally. - /// - /// The tool in `src/tools` reads the CI definition in `src/ci/builders.yml` and generates the - /// appropriate configuration for all our CI providers. This step ensures the tool was called - /// by the user before committing CI changes. - fn run(self, builder: &Builder<'_>) { - // NOTE: `.github/` is not included in dist-src tarballs - if !builder.src.join(".github/workflows/ci.yml").exists() { - builder.info("Skipping YAML anchors check: GitHub Actions config not found"); - return; - } - builder.info("Ensuring the YAML anchors in the GitHub Actions config were expanded"); - builder.run_delaying_failure( - builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src), - ); - } - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/expand-yaml-anchors") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(ExpandYamlAnchors); - } -} - fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf { builder.out.join(host.triple).join("test") } @@ -1371,6 +1336,7 @@ impl Step for RunMakeSupport { run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() }); } + /// Builds run-make-support and returns the path to the resulting rlib. fn run(self, builder: &Builder<'_>) -> PathBuf { builder.ensure(compile::Std::new(self.compiler, self.target)); @@ -1397,6 +1363,53 @@ impl Step for RunMakeSupport { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateRunMakeSupport { + host: TargetSelection, +} + +impl Step for CrateRunMakeSupport { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/run-make-support") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CrateRunMakeSupport { host: run.target }); + } + + /// Runs `cargo test` for run-make-support. + fn run(self, builder: &Builder<'_>) { + let host = self.host; + let compiler = builder.compiler(builder.top_stage, host); + + builder.ensure(compile::Std::new(compiler, host)); + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + host, + "test", + "src/tools/run-make-support", + SourceType::InTree, + &[], + ); + cargo.allow_features("test"); + run_cargo_test( + cargo, + &[], + &[], + "run-make-support", + "run-make-support self test", + compiler, + host, + builder, + ); + } +} + default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 994f0bef0dc74..2e2c5e9e6f8b2 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -302,7 +302,6 @@ bootstrap_tool!( RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RustInstaller, "src/tools/rust-installer", "rust-installer"; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; - ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; JsonDocCk, "src/tools/jsondocck", "jsondocck"; JsonDocLint, "src/tools/jsondoclint", "jsondoclint"; diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index f88c1b3ee8225..ca3756df4d779 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -1,3 +1,9 @@ +//! [Toolstate] checks to keep tools building +//! +//! Reachable via `./x.py test` but mostly relevant for CI, since it isn't run locally by default. +//! +//! [Toolstate]: https://forge.rust-lang.org/infra/toolstate.html + use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::utils::helpers::t; use serde_derive::{Deserialize, Serialize}; diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs new file mode 100644 index 0000000000000..68f1b1bef3f39 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -0,0 +1,61 @@ +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use std::path::PathBuf; +use std::process::Command; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub(crate) struct Vendor { + sync_args: Vec, + versioned_dirs: bool, + root_dir: PathBuf, +} + +impl Step for Vendor { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("placeholder").default_condition(true) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Vendor { + sync_args: run.builder.config.cmd.vendor_sync_args(), + versioned_dirs: run.builder.config.cmd.vendor_versioned_dirs(), + root_dir: run.builder.src.clone(), + }); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let mut cmd = Command::new(&builder.initial_cargo); + cmd.arg("vendor"); + + if self.versioned_dirs { + cmd.arg("--versioned-dirs"); + } + + // Sync these paths by default. + for p in [ + "src/tools/cargo/Cargo.toml", + "src/tools/rust-analyzer/Cargo.toml", + "compiler/rustc_codegen_cranelift/Cargo.toml", + "compiler/rustc_codegen_gcc/Cargo.toml", + "src/bootstrap/Cargo.toml", + ] { + cmd.arg("--sync").arg(builder.src.join(p)); + } + + // Also sync explicitly requested paths. + for sync_arg in self.sync_args { + cmd.arg("--sync").arg(sync_arg); + } + + // Will read the libstd Cargo.toml + // which uses the unstable `public-dependency` feature. + cmd.env("RUSTC_BOOTSTRAP", "1"); + + cmd.current_dir(self.root_dir); + + builder.run(&mut cmd); + } +} diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index adef9ebd0e306..0ad6c959309a2 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -14,8 +14,9 @@ use std::sync::OnceLock; use std::time::{Duration, Instant}; use crate::core::build_steps::tool::{self, SourceType}; -use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, setup, test}; -use crate::core::build_steps::{clippy, llvm}; +use crate::core::build_steps::{ + check, clean, clippy, compile, dist, doc, install, llvm, run, setup, test, vendor, +}; use crate::core::config::flags::{Color, Subcommand}; use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection}; use crate::prepare_behaviour_dump_dir; @@ -34,13 +35,34 @@ use once_cell::sync::Lazy; #[cfg(test)] mod tests; +/// Builds and performs different [`Self::kind`]s of stuff and actions, taking +/// into account build configuration from e.g. config.toml. pub struct Builder<'a> { + /// Build configuration from e.g. config.toml. pub build: &'a Build, + + /// The stage to use. Either implicitly determined based on subcommand, or + /// explicitly specified with `--stage N`. Normally this is the stage we + /// use, but sometimes we want to run steps with a lower stage than this. pub top_stage: u32, + + /// What to build or what action to perform. pub kind: Kind, + + /// A cache of outputs of [`Step`]s so we can avoid running steps we already + /// ran. cache: Cache, + + /// A stack of [`Step`]s to run before we can run this builder. The output + /// of steps is cached in [`Self::cache`]. stack: RefCell>>, + + /// The total amount of time we spent running [`Step`]s in [`Self::stack`]. time_spent_on_dependencies: Cell, + + /// The paths passed on the command line. Used by steps to figure out what + /// to do. For example: with `./x check foo bar` we get `paths=["foo", + /// "bar"]`. pub paths: Vec, } @@ -638,6 +660,7 @@ pub enum Kind { Run, Setup, Suggest, + Vendor, } impl Kind { @@ -658,6 +681,7 @@ impl Kind { Kind::Run => "run", Kind::Setup => "setup", Kind::Suggest => "suggest", + Kind::Vendor => "vendor", } } @@ -767,7 +791,6 @@ impl<'a> Builder<'a> { ), Kind::Test => describe!( crate::core::build_steps::toolstate::ToolStateCheck, - test::ExpandYamlAnchors, test::Tidy, test::Ui, test::Crashes, @@ -817,6 +840,7 @@ impl<'a> Builder<'a> { test::Clippy, test::RustDemangler, test::CompiletestTest, + test::CrateRunMakeSupport, test::RustdocJSStd, test::RustdocJSNotStd, test::RustdocGUI, @@ -908,7 +932,6 @@ impl<'a> Builder<'a> { install::Src, ), Kind::Run => describe!( - run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0, run::ReplaceVersionPlaceholder, @@ -920,6 +943,7 @@ impl<'a> Builder<'a> { ), Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), + Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() Kind::Format | Kind::Suggest => vec![], } @@ -992,6 +1016,7 @@ impl<'a> Builder<'a> { Kind::Setup, path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), ), + Subcommand::Vendor { .. } => (Kind::Vendor, &paths[..]), }; Self::new_internal(build, kind, paths.to_owned()) @@ -2099,13 +2124,10 @@ impl<'a> Builder<'a> { // during incremental builds" heuristic for the standard library. rustflags.arg("-Zinline-mir"); - // FIXME: always pass this after the next `#[cfg(bootstrap)]` update. - if compiler.stage != 0 { - // Similarly, we need to keep debug info for functions inlined into other std functions, - // even if we're not going to output debuginfo for the crate we're currently building, - // so that it'll be available when downstream consumers of std try to use it. - rustflags.arg("-Zinline-mir-preserve-debug"); - } + // Similarly, we need to keep debug info for functions inlined into other std functions, + // even if we're not going to output debuginfo for the crate we're currently building, + // so that it'll be available when downstream consumers of std try to use it. + rustflags.arg("-Zinline-mir-preserve-debug"); } if self.config.rustc_parallel diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2acce6273598c..ed45bc30362a5 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -345,6 +345,8 @@ pub struct Config { #[cfg(test)] pub initial_rustfmt: RefCell, + /// The paths to work with. For example: with `./x check foo bar` we get + /// `paths=["foo", "bar"]`. pub paths: Vec, } @@ -2027,7 +2029,8 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } => flags.stage.unwrap_or(0), + | Subcommand::Suggest { .. } + | Subcommand::Vendor { .. } => flags.stage.unwrap_or(0), }; // CI should always run stage 2 builds, unless it specifically states otherwise @@ -2054,7 +2057,8 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } => {} + | Subcommand::Suggest { .. } + | Subcommand::Vendor { .. } => {} } } @@ -2488,11 +2492,6 @@ impl Config { b } - // FIXME: "if-available" is deprecated. Remove this block later (around mid 2024) - // to not break builds between the recent-to-old checkouts. - Some(StringOrBool::String(s)) if s == "if-available" => { - llvm::is_ci_llvm_available(self, asserts) - } Some(StringOrBool::String(s)) if s == "if-unchanged" => if_unchanged(), Some(StringOrBool::String(other)) => { panic!("unrecognized option for download-ci-llvm: {:?}", other) diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index aaa2a2c47e079..f4ed7e76fba11 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -41,72 +41,72 @@ pub struct Flags { #[command(subcommand)] pub cmd: Subcommand, - #[arg(global(true), short, long, action = clap::ArgAction::Count)] + #[arg(global = true, short, long, action = clap::ArgAction::Count)] /// use verbose output (-vv for very verbose) pub verbose: u8, // each extra -v after the first is passed to Cargo - #[arg(global(true), short, long)] + #[arg(global = true, short, long)] /// use incremental compilation pub incremental: bool, - #[arg(global(true), long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")] + #[arg(global = true, long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")] /// TOML configuration file for build pub config: Option, - #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] + #[arg(global = true, long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] /// Build directory, overrides `build.build-dir` in `config.toml` pub build_dir: Option, - #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "BUILD")] + #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "BUILD")] /// build target of the stage0 compiler pub build: Option, - #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)] + #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)] /// host targets to build pub host: Option, - #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)] + #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)] /// target targets to build pub target: Option, - #[arg(global(true), long, value_name = "PATH")] + #[arg(global = true, long, value_name = "PATH")] /// build paths to exclude pub exclude: Vec, // keeping for client backward compatibility - #[arg(global(true), long, value_name = "PATH")] + #[arg(global = true, long, value_name = "PATH")] /// build paths to skip pub skip: Vec, - #[arg(global(true), long)] + #[arg(global = true, long)] /// include default paths in addition to the provided ones pub include_default_paths: bool, - #[arg(global(true), value_hint = clap::ValueHint::Other, long)] + #[arg(global = true, value_hint = clap::ValueHint::Other, long)] pub rustc_error_format: Option, - #[arg(global(true), long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")] + #[arg(global = true, long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")] /// command to run on failure pub on_fail: Option, - #[arg(global(true), long)] + #[arg(global = true, long)] /// dry run; don't build anything pub dry_run: bool, /// Indicates whether to dump the work done from bootstrap shims - #[arg(global(true), long)] + #[arg(global = true, long)] pub dump_bootstrap_shims: bool, - #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] + #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.) pub stage: Option, - #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] + #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage(s) to keep without recompiling /// (pass multiple times to keep e.g., both stages 0 and 1) pub keep_stage: Vec, - #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] + #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage(s) of the standard library to keep without recompiling /// (pass multiple times to keep e.g., both stages 0 and 1) pub keep_stage_std: Vec, - #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] + #[arg(global = true, long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] /// path to the root of the rust checkout pub src: Option, #[arg( - global(true), + global = true, short, long, value_hint = clap::ValueHint::Other, @@ -117,26 +117,26 @@ pub struct Flags { pub jobs: usize, // This overrides the deny-warnings configuration option, // which passes -Dwarnings to the compiler invocations. - #[arg(global(true), long)] + #[arg(global = true, long)] #[arg(value_enum, default_value_t=Warnings::Default, value_name = "deny|warn")] /// if value is deny, will deny warnings /// if value is warn, will emit warnings /// otherwise, use the default configured behaviour pub warnings: Warnings, - #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "FORMAT")] + #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "FORMAT")] /// rustc error format pub error_format: Option, - #[arg(global(true), long)] + #[arg(global = true, long)] /// use message-format=json pub json_output: bool, - #[arg(global(true), long, value_name = "STYLE")] + #[arg(global = true, long, value_name = "STYLE")] #[arg(value_enum, default_value_t = Color::Auto)] /// whether to use color in cargo and rustc output pub color: Color, - #[arg(global(true), long)] + #[arg(global = true, long)] /// Bootstrap uses this value to decide whether it should bypass locking the build process. /// This is rarely needed (e.g., compiling the std library for different targets in parallel). /// @@ -144,41 +144,41 @@ pub struct Flags { pub bypass_bootstrap_lock: bool, /// whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml - #[arg(global(true), long, value_name = "VALUE")] + #[arg(global = true, long, value_name = "VALUE")] pub llvm_skip_rebuild: Option, /// generate PGO profile with rustc build - #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] + #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub rust_profile_generate: Option, /// use PGO profile for rustc build - #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] + #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub rust_profile_use: Option, /// use PGO profile for LLVM build - #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] + #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub llvm_profile_use: Option, // LLVM doesn't support a custom location for generating profile // information. // // llvm_out/build/profiles/ is the location this writes to. /// generate PGO profile with llvm built for rustc - #[arg(global(true), long)] + #[arg(global = true, long)] pub llvm_profile_generate: bool, /// Enable BOLT link flags - #[arg(global(true), long)] + #[arg(global = true, long)] pub enable_bolt_settings: bool, /// Skip stage0 compiler validation - #[arg(global(true), long)] + #[arg(global = true, long)] pub skip_stage0_validation: bool, /// Additional reproducible artifacts that should be added to the reproducible artifacts archive. - #[arg(global(true), long)] + #[arg(global = true, long)] pub reproducible_artifact: Vec, - #[arg(global(true))] + #[arg(global = true)] /// paths for the subcommand pub paths: Vec, /// override options in config.toml - #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")] + #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")] pub set: Vec, /// arguments passed to subcommands - #[arg(global(true), last(true), value_name = "ARGS")] + #[arg(global = true, last(true), value_name = "ARGS")] pub free_args: Vec, } @@ -192,7 +192,7 @@ impl Flags { struct HelpVerboseOnly { #[arg(short, long)] help: bool, - #[arg(global(true), short, long, action = clap::ArgAction::Count)] + #[arg(global = true, short, long, action = clap::ArgAction::Count)] pub verbose: u8, #[arg(value_enum)] cmd: Kind, @@ -260,16 +260,16 @@ pub enum Subcommand { #[arg(long, requires = "fix")] allow_staged: bool, /// clippy lints to allow - #[arg(global(true), short = 'A', action = clap::ArgAction::Append, value_name = "LINT")] + #[arg(global = true, short = 'A', action = clap::ArgAction::Append, value_name = "LINT")] allow: Vec, /// clippy lints to deny - #[arg(global(true), short = 'D', action = clap::ArgAction::Append, value_name = "LINT")] + #[arg(global = true, short = 'D', action = clap::ArgAction::Append, value_name = "LINT")] deny: Vec, /// clippy lints to warn on - #[arg(global(true), short = 'W', action = clap::ArgAction::Append, value_name = "LINT")] + #[arg(global = true, short = 'W', action = clap::ArgAction::Append, value_name = "LINT")] warn: Vec, /// clippy lints to forbid - #[arg(global(true), short = 'F', action = clap::ArgAction::Append, value_name = "LINT")] + #[arg(global = true, short = 'F', action = clap::ArgAction::Append, value_name = "LINT")] forbid: Vec, }, /// Run cargo fix @@ -420,7 +420,7 @@ pub enum Subcommand { Arguments: This subcommand accepts a number of paths to tools to build and run. For example: - ./x.py run src/tools/expand-yaml-anchors + ./x.py run src/tools/bump-stage0 At least a tool needs to be called.")] /// Run tools contained in this repository Run { @@ -456,6 +456,15 @@ Arguments: #[arg(long)] run: bool, }, + /// Vendor dependencies + Vendor { + /// Additional `Cargo.toml` to sync and vendor + #[arg(long)] + sync: Vec, + /// Always include version in subdir name + #[arg(long)] + versioned_dirs: bool, + }, } impl Subcommand { @@ -476,6 +485,7 @@ impl Subcommand { Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, Subcommand::Suggest { .. } => Kind::Suggest, + Subcommand::Vendor { .. } => Kind::Vendor, } } @@ -581,6 +591,20 @@ impl Subcommand { _ => false, } } + + pub fn vendor_versioned_dirs(&self) -> bool { + match *self { + Subcommand::Vendor { versioned_dirs, .. } => versioned_dirs, + _ => false, + } + } + + pub fn vendor_sync_args(&self) -> Vec { + match self { + Subcommand::Vendor { sync, .. } => sync.clone(), + _ => vec![], + } + } } /// Returns the shell completion for a given shell, if the result differs from the current diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index e03b1e179084e..6ccf29fb6cbef 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -14,6 +14,7 @@ use std::ffi::{OsStr, OsString}; use std::fs; use std::path::PathBuf; use std::process::Command; +use walkdir::WalkDir; use crate::builder::Kind; use crate::core::config::Target; @@ -177,6 +178,34 @@ than building it. continue; } + // Check if there exists a built-in target in the list of supported targets. + let mut has_target = false; + let target_str = target.to_string(); + + let supported_target_list = + output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"])); + + has_target |= supported_target_list.contains(&target_str); + + // If not, check for a valid file location that may have been specified + // by the user for the custom target. + if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") { + let mut target_os_str = OsString::from(&target_str); + target_os_str.push(".json"); + // Recursively traverse through nested directories. + let walker = WalkDir::new(custom_target_path).into_iter(); + for entry in walker.filter_map(|e| e.ok()) { + has_target |= entry.file_name() == target_os_str; + } + } + + if !has_target && !["A", "B", "C"].contains(&target_str.as_str()) { + panic!( + "No such target exists in the target list, + specify a correct location of the JSON specification file for custom targets!" + ); + } + if !build.config.dry_run() { cmd_finder.must_have(build.cc(*target)); if let Some(ar) = build.ar(*target) { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 663a2d8e17cb5..c599709a32279 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -376,11 +376,16 @@ impl Build { .expect("failed to read src/version"); let version = version.trim(); - let bootstrap_out = std::env::current_exe() + let mut bootstrap_out = std::env::current_exe() .expect("could not determine path to running process") .parent() .unwrap() .to_path_buf(); + // Since bootstrap is hardlink to deps/bootstrap-*, Solaris can sometimes give + // path with deps/ which is bad and needs to be avoided. + if bootstrap_out.ends_with("deps") { + bootstrap_out.pop(); + } if !bootstrap_out.join(exe("rustc", config.build)).exists() && !cfg!(test) { // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented panic!( diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 0eff7ca5962bb..d0da7d3066013 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -42,11 +42,10 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 -ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ - # Check library crates on all tier 1 targets. - # We disable optimized compiler built-ins because that requires a C toolchain for the target. - # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. - python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ +# Check library crates on all tier 1 targets. +# We disable optimized compiler built-ins because that requires a C toolchain for the target. +# We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. +ENV SCRIPT python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py clippy bootstrap -Dwarnings && \ python3 ../x.py clippy compiler library -Aclippy::all -Dclippy::correctness && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index d6de992913bf5..9cc508fe92881 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -5,7 +5,7 @@ set -euf -o pipefail -INTEGRATION_SHA=56310bca298872ffb5ea02e665956d9b6dc41171 +INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 PICK_REFS=() checkout=fuchsia diff --git a/src/ci/docker/scripts/build-fuchsia-toolchain.sh b/src/ci/docker/scripts/build-fuchsia-toolchain.sh index beea2f522fde9..7a0d4fcffc156 100755 --- a/src/ci/docker/scripts/build-fuchsia-toolchain.sh +++ b/src/ci/docker/scripts/build-fuchsia-toolchain.sh @@ -4,13 +4,13 @@ set -ex source shared.sh FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64 -FUCHSIA_SDK_ID=MrhQwtmP8CpZre-i_PNOREcThbUcrX3bA-45d6WQr-cC -FUCHSIA_SDK_SHA256=32b850c2d98ff02a59adefa2fcf34e44471385b51cad7ddb03ee3977a590afe7 +FUCHSIA_SDK_ID=version:20.20240412.3.1 +FUCHSIA_SDK_SHA256=cc52f3497487dd813c89d9316e6967efcea89c7759edccf3e40fcf3662e53f19 FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk CLANG_DOWNLOAD_URL=\ https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64 -CLANG_DOWNLOAD_ID=Tpc85d1ZwSlZ6UKl2d96GRUBGNA5JKholOKe24sRDr0C -CLANG_DOWNLOAD_SHA256=4e973ce5dd59c12959e942a5d9df7a19150118d03924a86894e29edb8b110ebd +CLANG_DOWNLOAD_ID=git_revision:c777c011a709dffd4fa5e79cad7947b7c3405d02 +CLANG_DOWNLOAD_SHA256=779167422ad73c292f049dcea5569f84577af9292189ed2749518b966a4d0844 install_clang() { mkdir -p clang_download diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 437b51641fc92..8ac00a8863f6f 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -280,7 +280,7 @@ def start(self): # Look up the product bundle transfer manifest. self.log_info("Looking up the product bundle transfer manifest...") product_name = "minimal." + self.triple_to_arch(self.target) - fuchsia_version = "14.20230811.2.1" + fuchsia_version = "20.20240412.3.1" # FIXME: We should be able to replace this with the machine parsable # `ffx --machine json product lookup ...` once F15 is released. diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py new file mode 100755 index 0000000000000..68565f489c939 --- /dev/null +++ b/src/ci/github-actions/calculate-job-matrix.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 + +""" +This script serves for generating a matrix of jobs that should +be executed on CI. + +It reads job definitions from `src/ci/github-actions/jobs.yml` +and filters them based on the event that happened on CI. +""" +import dataclasses +import enum +import json +import logging +import os +from pathlib import Path +from typing import List, Dict, Any, Optional + +import yaml + +CI_DIR = Path(__file__).absolute().parent.parent +JOBS_YAML_PATH = Path(__file__).absolute().parent / "jobs.yml" + +Job = Dict[str, Any] + + +def name_jobs(jobs: List[Dict], prefix: str) -> List[Job]: + """ + Add a `name` attribute to each job, based on its image and the given `prefix`. + """ + for job in jobs: + job["name"] = f"{prefix} - {job['image']}" + return jobs + + +def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: + """ + Prepends `environment` to the `env` attribute of each job. + The `env` of each job has higher precedence than `environment`. + """ + for job in jobs: + env = environment.copy() + env.update(job.get("env", {})) + job["env"] = env + return jobs + + +class WorkflowRunType(enum.Enum): + PR = enum.auto() + Try = enum.auto() + Auto = enum.auto() + + +@dataclasses.dataclass +class GitHubCtx: + event_name: str + ref: str + repository: str + + +def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: + if ctx.event_name == "pull_request": + return WorkflowRunType.PR + elif ctx.event_name == "push": + old_bors_try_build = ( + ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and + ctx.repository == "rust-lang-ci/rust" + ) + new_bors_try_build = ( + ctx.ref == "refs/heads/automation/bors/try" and + ctx.repository == "rust-lang/rust" + ) + try_build = old_bors_try_build or new_bors_try_build + + if try_build: + return WorkflowRunType.Try + + if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust": + return WorkflowRunType.Auto + + return None + + +def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]: + if run_type == WorkflowRunType.PR: + return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"]) + elif run_type == WorkflowRunType.Try: + return add_base_env(name_jobs(job_data["try"], "try"), job_data["envs"]["try"]) + elif run_type == WorkflowRunType.Auto: + return add_base_env(name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"]) + + return [] + + +def skip_jobs(jobs: List[Dict[str, Any]], channel: str) -> List[Job]: + """ + Skip CI jobs that are not supposed to be executed on the given `channel`. + """ + return [j for j in jobs if j.get("only_on_channel", channel) == channel] + + +def get_github_ctx() -> GitHubCtx: + return GitHubCtx( + event_name=os.environ["GITHUB_EVENT_NAME"], + ref=os.environ["GITHUB_REF"], + repository=os.environ["GITHUB_REPOSITORY"] + ) + + +def format_run_type(run_type: WorkflowRunType) -> str: + if run_type == WorkflowRunType.PR: + return "pr" + elif run_type == WorkflowRunType.Auto: + return "auto" + elif run_type == WorkflowRunType.Try: + return "try" + else: + raise AssertionError() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + + with open(JOBS_YAML_PATH) as f: + data = yaml.safe_load(f) + + github_ctx = get_github_ctx() + + run_type = find_run_type(github_ctx) + logging.info(f"Job type: {run_type}") + + with open(CI_DIR / "channel") as f: + channel = f.read().strip() + + jobs = [] + if run_type is not None: + jobs = calculate_jobs(run_type, data) + jobs = skip_jobs(jobs, channel) + run_type = format_run_type(run_type) + + logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") + print(f"jobs={json.dumps(jobs)}") + print(f"run_type={run_type}") diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml deleted file mode 100644 index de71b9f874f8d..0000000000000 --- a/src/ci/github-actions/ci.yml +++ /dev/null @@ -1,808 +0,0 @@ -###################################################### -# WARNING! Action needed when changing this file # -###################################################### - -# Due to GitHub Actions limitations, we can't use YAML Anchors directly in the -# CI configuration stored on the repository. To work around that this file is -# expanded by a tool in the repository, and the expansion is committed as well. -# -# After you make any change to the file you'll need to run this command: -# -# ./x.py run src/tools/expand-yaml-anchors -# -# ...and commit the file it updated in addition to this one. If you forget this -# step CI will fail. - ---- -############################### -# YAML Anchors Definition # -############################### - -# This key contains most of the YAML anchors that will be used later in the -# document. YAML anchors allows us to greatly reduce duplication inside the CI -# configuration by reusing parts of the configuration. -# -# YAML anchors work by defining an anchor with `&anchor-name` and reusing its -# content in another place with `*anchor-name`. The special `<<` map key merges -# the content of the map with the content of the anchor (or list of anchors). -# -# The expand-yaml-anchors tool will automatically remove this block from the -# output YAML file. -x--expand-yaml-anchors--remove: - - &shared-ci-variables - CI_JOB_NAME: ${{ matrix.name }} - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. - HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - &public-variables - SCCACHE_BUCKET: rust-lang-ci-sccache2 - TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate - CACHE_DOMAIN: ci-caches.rust-lang.org - - - &prod-variables - SCCACHE_BUCKET: rust-lang-ci-sccache2 - DEPLOY_BUCKET: rust-lang-ci2 - TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate - TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues - TOOLSTATE_PUBLISH: 1 - # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named - # AWS_SECRET_ACCESS_KEY_. Including the key id in the name allows to - # rotate them in a single branch while keeping the old key in another - # branch, which wouldn't be possible if the key was named with the kind - # (caches, artifacts...). - CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 - AWS_REGION: us-west-1 - CACHE_DOMAIN: ci-caches.rust-lang.org - - - &dummy-variables - SCCACHE_BUCKET: rust-lang-gha-caches - DEPLOY_BUCKET: rust-lang-gha - TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate - TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/pietroalbini/rust-toolstate/issues - TOOLSTATE_PUBLISH: 1 - # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named - # AWS_SECRET_ACCESS_KEY_. Including the key id in the name allows to - # rotate them in a single branch while keeping the old key in another - # branch, which wouldn't be possible if the key was named with the kind - # (caches, artifacts...). - CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5 - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF - AWS_REGION: us-west-1 - CACHE_DOMAIN: ci-caches-gha.rust-lang.org - - - &base-job - env: {} - - - &job-linux-4c - os: ubuntu-20.04-4core-16gb - <<: *base-job - - - &job-linux-8c - os: ubuntu-20.04-8core-32gb - <<: *base-job - - - &job-linux-16c - os: ubuntu-20.04-16core-64gb - <<: *base-job - - - &job-macos-xl - os: macos-13 # We use the standard runner for now - <<: *base-job - - - &job-macos-m1 - os: macos-14 - <<: *base-job - - - &job-windows-8c - os: windows-2019-8core-32gb - <<: *base-job - - - &job-windows-16c - os: windows-2019-16core-64gb - <<: *base-job - - - &job-aarch64-linux - os: [self-hosted, ARM64, linux] - - - &step - if: success() && !env.SKIP_JOB - - - &base-ci-job - defaults: - run: - shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} - timeout-minutes: 600 - runs-on: "${{ matrix.os }}" - env: *shared-ci-variables - steps: - - if: contains(matrix.os, 'windows') - uses: msys2/setup-msys2@v2.22.0 - with: - # i686 jobs use mingw32. x86_64 and cross-compile jobs use mingw64. - msystem: ${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }} - # don't try to download updates for already installed packages - update: false - # don't try to use the msys that comes built-in to the github runner, - # so we can control what is installed (i.e. not python) - release: true - # Inherit the full path from the Windows environment, with MSYS2's */bin/ - # dirs placed in front. This lets us run Windows-native Python etc. - path-type: inherit - install: > - make - dos2unix - diffutils - - - name: disable git crlf conversion - run: git config --global core.autocrlf false - - - name: checkout the source code - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - # Rust Log Analyzer can't currently detect the PR number of a GitHub - # Actions build on its own, so a hint in the log message is needed to - # point it in the right direction. - - name: configure the PR in which the error message will be posted - run: echo "[CI_PR_NUMBER=$num]" - env: - num: ${{ github.event.number }} - if: success() && !env.SKIP_JOB && github.event_name == 'pull_request' - - - name: add extra environment variables - run: src/ci/scripts/setup-environment.sh - env: - # Since it's not possible to merge `${{ matrix.env }}` with the other - # variables in `job..env`, the variables defined in the matrix - # are passed to the `setup-environment.sh` script encoded in JSON, - # which then uses log commands to actually set them. - EXTRA_VARIABLES: ${{ toJson(matrix.env) }} - <<: *step - - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - <<: *step - - - name: ensure the channel matches the target branch - run: src/ci/scripts/verify-channel.sh - <<: *step - - - name: collect CPU statistics - run: src/ci/scripts/collect-cpu-stats.sh - <<: *step - - - name: show the current environment - run: src/ci/scripts/dump-environment.sh - <<: *step - - - name: install awscli - run: src/ci/scripts/install-awscli.sh - <<: *step - - - name: install sccache - run: src/ci/scripts/install-sccache.sh - <<: *step - - - name: select Xcode - run: src/ci/scripts/select-xcode.sh - <<: *step - - - name: install clang - run: src/ci/scripts/install-clang.sh - <<: *step - - - name: install tidy - run: src/ci/scripts/install-tidy.sh - <<: *step - - - name: install WIX - run: src/ci/scripts/install-wix.sh - <<: *step - - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - <<: *step - - - name: checkout submodules - run: src/ci/scripts/checkout-submodules.sh - <<: *step - - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh - <<: *step - - - name: install MinGW - run: src/ci/scripts/install-mingw.sh - <<: *step - - - name: install ninja - run: src/ci/scripts/install-ninja.sh - <<: *step - - - name: enable ipv6 on Docker - run: src/ci/scripts/enable-docker-ipv6.sh - <<: *step - - # Disable automatic line ending conversion (again). On Windows, when we're - # installing dependencies, something switches the git configuration directory or - # re-enables autocrlf. We've not tracked down the exact cause -- and there may - # be multiple -- but this should ensure submodules are checked out with the - # appropriate line endings. - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - <<: *step - - - name: ensure line endings are correct - run: src/ci/scripts/verify-line-endings.sh - <<: *step - - - name: ensure backported commits are in upstream branches - run: src/ci/scripts/verify-backported-commits.sh - <<: *step - - - name: ensure the stable version number is correct - run: src/ci/scripts/verify-stable-version-number.sh - <<: *step - - - name: run the build - # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. - run: src/ci/scripts/run-build-from-ci.sh 2>&1 - env: - AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} - TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} - <<: *step - - - name: create github artifacts - run: src/ci/scripts/create-doc-artifacts.sh - <<: *step - - - name: upload artifacts to github - uses: actions/upload-artifact@v4 - with: - # name is set in previous step - name: ${{ env.DOC_ARTIFACT_NAME }} - path: obj/artifacts/doc - if-no-files-found: ignore - retention-days: 5 - <<: *step - - - name: upload artifacts to S3 - run: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }} - # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy - # builders *should* have the AWS credentials available. Still, explicitly - # adding the condition is helpful as this way CI will not silently skip - # deploying artifacts from a dist builder if the variables are misconfigured, - # erroring about invalid credentials instead. - if: success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1') - <<: *step - - # These snippets are used by the try-success, try-failure, auto-success and auto-failure jobs. - # Check out their documentation for more information on why they're needed. - - - &base-outcome-job - name: bors build finished - runs-on: ubuntu-latest - - - &base-success-job - steps: - - name: mark the job as a success - run: exit 0 - shell: bash - <<: *base-outcome-job - - - &base-failure-job - steps: - - name: mark the job as a failure - run: exit 1 - shell: bash - <<: *base-outcome-job - -########################### -# Builders definition # -########################### - -name: CI -on: - push: - branches: - - auto - - try - - try-perf - - automation/bors/try - - master - pull_request: - branches: - - "**" - -permissions: - contents: read - packages: write - -defaults: - run: - # On Linux, macOS, and Windows, use the system-provided bash as the default - # shell. (This should only make a difference on Windows, where the default - # shell is PowerShell.) - shell: bash - -concurrency: - # For a given workflow, if we push to the same branch, cancel all previous builds on that branch. - # We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which - # are all triggered on the same branch, but which should be able to run concurrently. - group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }} - cancel-in-progress: true - -jobs: - # The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml. - calculate_matrix: - name: Calculate job matrix - runs-on: ubuntu-latest - outputs: - jobs: ${{ steps.jobs.outputs.jobs }} - steps: - - name: Checkout the source code - uses: actions/checkout@v4 - - name: Calculate the CI job matrix - run: python3 src/ci/scripts/calculate-job-matrix.py >> $GITHUB_OUTPUT - id: jobs - pr: - <<: *base-ci-job - name: PR - ${{ matrix.name }} - needs: [ calculate_matrix ] - env: - <<: [*shared-ci-variables, *public-variables] - PR_CI_JOB: 1 - if: github.event_name == 'pull_request' - continue-on-error: ${{ matrix.name == 'mingw-check-tidy' }} - strategy: - matrix: - # Check the `calculate_matrix` job to see how is the matrix defined. - include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} - - auto: - <<: *base-ci-job - name: auto - ${{ matrix.name }} - env: - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' - strategy: - matrix: - include: - ############################# - # Linux/Docker builders # - ############################# - - - name: aarch64-gnu - <<: *job-aarch64-linux - - - name: arm-android - <<: *job-linux-8c - - - name: armhf-gnu - <<: *job-linux-8c - - - name: dist-aarch64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-8c - - - name: dist-android - <<: *job-linux-8c - - - name: dist-arm-linux - <<: *job-linux-16c - - - name: dist-armhf-linux - <<: *job-linux-8c - - - name: dist-armv7-linux - <<: *job-linux-8c - - - name: dist-i586-gnu-i586-i686-musl - <<: *job-linux-8c - - - name: dist-i686-linux - <<: *job-linux-8c - - - name: dist-loongarch64-linux - <<: *job-linux-8c - - - name: dist-ohos - <<: *job-linux-8c - - - name: dist-powerpc-linux - <<: *job-linux-8c - - - name: dist-powerpc64-linux - <<: *job-linux-8c - - - name: dist-powerpc64le-linux - <<: *job-linux-8c - - - name: dist-riscv64-linux - <<: *job-linux-8c - - - name: dist-s390x-linux - <<: *job-linux-8c - - - name: dist-various-1 - <<: *job-linux-8c - - - name: dist-various-2 - <<: *job-linux-8c - - - name: dist-x86_64-freebsd - <<: *job-linux-8c - - - name: dist-x86_64-illumos - <<: *job-linux-8c - - - &dist-x86_64-linux - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - - - name: dist-x86_64-linux-alt - env: - IMAGE: dist-x86_64-linux - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - - - name: dist-x86_64-musl - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-8c - - - name: dist-x86_64-netbsd - <<: *job-linux-8c - - - name: i686-gnu - <<: *job-linux-8c - - - name: i686-gnu-nopt - <<: *job-linux-8c - - - name: mingw-check - <<: *job-linux-4c - - - name: test-various - <<: *job-linux-8c - - - name: x86_64-gnu - <<: *job-linux-4c - - # This job ensures commits landing on nightly still pass the full - # test suite on the stable channel. There are some UI tests that - # depend on the channel being built (for example if they include the - # channel name on the output), and this builder prevents landing - # changes that would result in broken builds after a promotion. - - name: x86_64-gnu-stable - env: - IMAGE: x86_64-gnu - RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable - # Only run this job on the nightly channel. Running this on beta - # could cause failures when `dev: 1` in `stage0.txt`, and running - # this on stable is useless. - CI_ONLY_WHEN_CHANNEL: nightly - <<: *job-linux-4c - - - name: x86_64-gnu-aux - <<: *job-linux-4c - - - name: x86_64-gnu-integration - env: - # Only run this job on the nightly channel. Fuchsia requires - # nightly features to compile, and this job would fail if - # executed on beta and stable. - CI_ONLY_WHEN_CHANNEL: nightly - <<: *job-linux-8c - - - name: x86_64-gnu-debug - <<: *job-linux-8c - - - name: x86_64-gnu-distcheck - <<: *job-linux-8c - - - name: x86_64-gnu-llvm-18 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - - name: x86_64-gnu-llvm-17 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - - name: x86_64-gnu-nopt - <<: *job-linux-4c - - - name: x86_64-gnu-tools - env: - DEPLOY_TOOLSTATES_JSON: toolstates-linux.json - <<: *job-linux-8c - - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin - RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-macos-xl - - - name: dist-apple-various - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim - RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl - - - name: x86_64-apple-1 - env: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - MACOSX_STD_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl - - - name: x86_64-apple-2 - env: - SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps - <<: *env-x86_64-apple-tests - <<: *job-macos-xl - - # This target only needs to support 11.0 and up as nothing else supports the hardware - - name: dist-aarch64-apple - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin - RUST_CONFIGURE_ARGS: >- - --enable-full-tools - --enable-sanitizers - --enable-profiler - --set rust.jemalloc - --set llvm.ninja=false - --set rust.lto=thin - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-m1 - - # This target only needs to support 11.0 and up as nothing else supports the hardware - - name: aarch64-apple - env: - SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin - RUST_CONFIGURE_ARGS: >- - --enable-sanitizers - --enable-profiler - --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-m1 - - ###################### - # Windows Builders # - ###################### - - - name: x86_64-msvc - env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-msvc - <<: *job-windows-8c - - - name: i686-msvc - env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-msvc - <<: *job-windows-8c - - - name: x86_64-msvc-ext - env: - SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows - HOST_TARGET: x86_64-pc-windows-msvc - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json - DEPLOY_TOOLSTATES_JSON: toolstates-windows.json - <<: *job-windows-8c - - # 32/64-bit MinGW builds. - # - # We are using MinGW with POSIX threads since LLVM requires - # C++'s std::thread which is disabled in libstdc++ with win32 threads. - # FIXME: Libc++ doesn't have this limitation so we can avoid - # winpthreads if we switch to it. - # - # Instead of relying on the MinGW version installed on CI we download - # and install one ourselves so we won't be surprised by changes to CI's - # build image. - # - # Finally, note that the downloads below are all in the `rust-lang-ci` S3 - # bucket, but they clearly didn't originate there! The downloads originally - # came from the mingw-w64 SourceForge download site. Unfortunately - # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - - name: i686-mingw - env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: x86_64-mingw - env: - SCRIPT: make ci-mingw - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: dist-x86_64-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-msvc - --host=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc - --enable-full-tools - --enable-profiler - --set rust.codegen-units=1 - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-i686-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-msvc - --host=i686-pc-windows-msvc - --target=i686-pc-windows-msvc,i586-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-aarch64-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-msvc - --host=aarch64-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-i686-mingw - env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --enable-full-tools - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - SCRIPT: python x.py dist bootstrap --include-default-paths - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-x86_64-mingw - env: - SCRIPT: python x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-full-tools - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-x86_64-msvc-alt - env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - <<: *job-windows-8c - - try: - <<: *base-ci-job - name: try - ${{ matrix.name }} - env: - DIST_TRY_BUILD: 1 - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && (((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust') || ((github.ref == 'refs/heads/automation/bors/try') && github.repository == 'rust-lang/rust')) - strategy: - matrix: - include: - - &dist-x86_64-linux - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - - - master: - name: master - runs-on: ubuntu-latest - env: - <<: [*prod-variables] - if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust' - steps: - - name: checkout the source code - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - - name: publish toolstate - run: src/ci/publish_toolstate.sh - shell: bash - env: - TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} - <<: *step - - # These jobs don't actually test anything, but they're used to tell bors the - # build completed, as there is no practical way to detect when a workflow is - # successful listening to webhooks only. - try-success: - needs: [try] - if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" - <<: *base-success-job - try-failure: - needs: [try] - if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" - <<: *base-failure-job - auto-success: - needs: [auto] - if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" - <<: *base-success-job - auto-failure: - needs: [auto] - if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" - <<: *base-failure-job diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 7e89eef2670e4..1fabf889e38a1 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -1,8 +1,6 @@ # This file contains definitions of CI job parameters that are loaded # dynamically in CI from ci.yml. -# You *do not* need to re-run `src/tools/expand-yaml-anchors` when you -# modify this file. -shared_defs: +runners: - &base-job env: { } @@ -37,14 +35,429 @@ shared_defs: - &job-aarch64-linux os: [ self-hosted, ARM64, linux ] +envs: + production: + &production + DEPLOY_BUCKET: rust-lang-ci2 + TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues + TOOLSTATE_PUBLISH: 1 + # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named + # AWS_SECRET_ACCESS_KEY_. Including the key id in the name allows to + # rotate them in a single branch while keeping the old key in another + # branch, which wouldn't be possible if the key was named with the kind + # (caches, artifacts...). + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + AWS_REGION: us-west-1 + + try: + <<: *production + DIST_TRY_BUILD: 1 + + auto: + <<: *production + + pr: + PR_CI_JOB: 1 + +# Jobs that run on each push to a pull request (PR) +# These jobs automatically inherit envs.pr, to avoid repeating +# it in each job definition. pr: - - name: mingw-check + - image: mingw-check <<: *job-linux-4c - - name: mingw-check-tidy + - image: mingw-check-tidy + continue_on_error: true <<: *job-linux-4c - - name: x86_64-gnu-llvm-17 + - image: x86_64-gnu-llvm-17 env: ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c - - name: x86_64-gnu-tools + - image: x86_64-gnu-tools + <<: *job-linux-16c + +# Jobs that run when you perform a try build (@bors try) +# These jobs automatically inherit envs.try, to avoid repeating +# it in each job definition. +try: + - image: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-16c + +# Main CI jobs that have to be green to merge a commit into master +# These jobs automatically inherit envs.auto, to avoid repeating +# it in each job definition. +auto: + ############################# + # Linux/Docker builders # + ############################# + + - image: aarch64-gnu + <<: *job-aarch64-linux + + - image: arm-android + <<: *job-linux-8c + + - image: armhf-gnu + <<: *job-linux-8c + + - image: dist-aarch64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-8c + + - image: dist-android + <<: *job-linux-8c + + - image: dist-arm-linux + <<: *job-linux-16c + + - image: dist-armhf-linux + <<: *job-linux-8c + + - image: dist-armv7-linux + <<: *job-linux-8c + + - image: dist-i586-gnu-i586-i686-musl + <<: *job-linux-8c + + - image: dist-i686-linux + <<: *job-linux-8c + + - image: dist-loongarch64-linux + <<: *job-linux-8c + + - image: dist-ohos + <<: *job-linux-8c + + - image: dist-powerpc-linux + <<: *job-linux-8c + + - image: dist-powerpc64-linux + <<: *job-linux-8c + + - image: dist-powerpc64le-linux + <<: *job-linux-8c + + - image: dist-riscv64-linux + <<: *job-linux-8c + + - image: dist-s390x-linux + <<: *job-linux-8c + + - image: dist-various-1 + <<: *job-linux-8c + + - image: dist-various-2 + <<: *job-linux-8c + + - image: dist-x86_64-freebsd + <<: *job-linux-8c + + - image: dist-x86_64-illumos + <<: *job-linux-8c + + - image: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-16c + + - image: dist-x86_64-linux-alt + env: + IMAGE: dist-x86_64-linux + CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-16c + + - image: dist-x86_64-musl + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-8c + + - image: dist-x86_64-netbsd + <<: *job-linux-8c + + - image: i686-gnu + <<: *job-linux-8c + + - image: i686-gnu-nopt + <<: *job-linux-8c + + - image: mingw-check + <<: *job-linux-4c + + - image: test-various + <<: *job-linux-8c + + - image: x86_64-gnu + <<: *job-linux-4c + + # This job ensures commits landing on nightly still pass the full + # test suite on the stable channel. There are some UI tests that + # depend on the channel being built (for example if they include the + # channel name on the output), and this builder prevents landing + # changes that would result in broken builds after a promotion. + - image: x86_64-gnu-stable + # Only run this job on the nightly channel. Running this on beta + # could cause failures when `dev: 1` in `stage0.txt`, and running + # this on stable is useless. + only_on_channel: nightly + env: + IMAGE: x86_64-gnu + RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable + <<: *job-linux-4c + + - image: x86_64-gnu-aux + <<: *job-linux-4c + + - image: x86_64-gnu-integration + # Only run this job on the nightly channel. Fuchsia requires + # nightly features to compile, and this job would fail if + # executed on beta and stable. + only_on_channel: nightly + <<: *job-linux-8c + + - image: x86_64-gnu-debug + <<: *job-linux-8c + + - image: x86_64-gnu-distcheck + <<: *job-linux-8c + + - image: x86_64-gnu-llvm-18 + env: + RUST_BACKTRACE: 1 + <<: *job-linux-8c + + - image: x86_64-gnu-llvm-17 + env: + RUST_BACKTRACE: 1 + <<: *job-linux-8c + + - image: x86_64-gnu-nopt + <<: *job-linux-4c + + - image: x86_64-gnu-tools + env: + DEPLOY_TOOLSTATES_JSON: toolstates-linux.json + <<: *job-linux-8c + + #################### + # macOS Builders # + #################### + + - image: dist-x86_64-apple + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin + RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-macos-xl + + - image: dist-apple-various + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim + RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-xl + + - image: x86_64-apple-1 + env: &env-x86_64-apple-tests + SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + MACOSX_STD_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-xl + + - image: x86_64-apple-2 + env: + SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps + <<: *env-x86_64-apple-tests + <<: *job-macos-xl + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - image: dist-aarch64-apple + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-full-tools + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + --set llvm.ninja=false + --set rust.lto=thin + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-m1 + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - image: aarch64-apple + env: + SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-m1 + + ###################### + # Windows Builders # + ###################### + + - image: x86_64-msvc + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-msvc + <<: *job-windows-8c + + - image: i686-msvc + env: + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + SCRIPT: make ci-msvc + <<: *job-windows-8c + + - image: x86_64-msvc-ext + env: + SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows + HOST_TARGET: x86_64-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json + DEPLOY_TOOLSTATES_JSON: toolstates-windows.json + <<: *job-windows-8c + + # 32/64-bit MinGW builds. + # + # We are using MinGW with POSIX threads since LLVM requires + # C++'s std::thread which is disabled in libstdc++ with win32 threads. + # FIXME: Libc++ doesn't have this limitation so we can avoid + # winpthreads if we switch to it. + # + # Instead of relying on the MinGW version installed on CI we download + # and install one ourselves so we won't be surprised by changes to CI's + # build image. + # + # Finally, note that the downloads below are all in the `rust-lang-ci` S3 + # bucket, but they clearly didn't originate there! The downloads originally + # came from the mingw-w64 SourceForge download site. Unfortunately + # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. + + - image: i686-mingw + env: + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + SCRIPT: make ci-mingw + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + <<: *job-windows-8c + + - image: x86_64-mingw + env: + SCRIPT: make ci-mingw + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + <<: *job-windows-8c + + - image: dist-x86_64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=x86_64-pc-windows-msvc + --target=x86_64-pc-windows-msvc + --enable-full-tools + --enable-profiler + --set rust.codegen-units=1 + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-i686-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-msvc + --host=i686-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=aarch64-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-i686-mingw + env: + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --enable-full-tools + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + SCRIPT: python x.py dist bootstrap --include-default-paths + CUSTOM_MINGW: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-x86_64-mingw + env: + SCRIPT: python x.py dist bootstrap --include-default-paths + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-full-tools + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-x86_64-msvc-alt + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + <<: *job-windows-8c diff --git a/src/ci/scripts/calculate-job-matrix.py b/src/ci/scripts/calculate-job-matrix.py deleted file mode 100755 index 9b1e74c23c324..0000000000000 --- a/src/ci/scripts/calculate-job-matrix.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -""" -This script serves for generating a matrix of jobs that should -be executed on CI. - -It reads job definitions from `src/ci/github-actions/jobs.yml` -and filters them based on the event that happened on CI. - -Currently, it only supports PR builds. -""" - -import json -from pathlib import Path - -import yaml - -JOBS_YAML_PATH = Path(__file__).absolute().parent.parent / "github-actions" / "jobs.yml" - - -if __name__ == "__main__": - with open(JOBS_YAML_PATH) as f: - jobs = yaml.safe_load(f) - job_output = jobs["pr"] - print(f"jobs={json.dumps(job_output)}") diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh deleted file mode 100755 index 48127166ad080..0000000000000 --- a/src/ci/scripts/should-skip-this.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Set the SKIP_JOB environment variable if this job is not supposed to run on the current builder. - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - -if [[ -n "${CI_ONLY_WHEN_CHANNEL-}" ]]; then - if [[ "${CI_ONLY_WHEN_CHANNEL}" = "$(cat src/ci/channel)" ]]; then - echo "The channel is the expected one" - else - echo "Not executing this job as the channel is not the expected one" - ciCommandSetEnv SKIP_JOB 1 - exit 0 - fi -fi - - -echo "Executing the job since there is no skip rule preventing the execution" -exit 0 diff --git a/src/doc/book b/src/doc/book index 3131aa4642c62..d207d894cc5e1 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 3131aa4642c627a24f523c82566b94a7d920f68c +Subproject commit d207d894cc5e1d496ab99beeacd1a420e5d4d238 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index eb3eb80e106d0..0c68e90acaae5 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit eb3eb80e106d03250c1fb7c5666b1c8c59672862 +Subproject commit 0c68e90acaae5a611f8f5098a3c2980de9845ab2 diff --git a/src/doc/reference b/src/doc/reference index 55694913b1301..5854fcc286557 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 55694913b1301cc809f9bf4a1ad1b3d6920efbd9 +Subproject commit 5854fcc286557ad3ab34d325073d11d8118096b6 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index b77a34bd46399..07425fed36b00 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit b77a34bd46399687b4ce6a17198e9f316c988794 +Subproject commit 07425fed36b00e60341c5e29e28d37d40cbd4451 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 31096b6df92b2..c9c0ee4067f1b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -3,6 +3,7 @@ - [What is rustc?](what-is-rustc.md) - [Command-line Arguments](command-line-arguments.md) - [Codegen Options](codegen-options/index.md) +- [Jobserver](jobserver.md) - [Lints](lints/index.md) - [Lint Levels](lints/levels.md) - [Lint Groups](lints/groups.md) @@ -55,6 +56,11 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) + - [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md) + - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) + - [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md) + - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) + - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) - [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 673ff12b5ceb0..babe2bc342bb0 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -42,6 +42,18 @@ generated code, but may be slower to compile. The default value, if not specified, is 16 for non-incremental builds. For incremental builds the default is 256 which allows caching to be more granular. +## collapse-macro-debuginfo + +This flag controls whether code locations from a macro definition are collapsed into a single +location associated with that macro's call site, when generating debuginfo for this crate. + +This option, if passed, overrides both default collapsing behavior and `#[collapse_debuginfo]` +attributes in code. + +* `y`, `yes`, `on`, `true`: collapse code locations in debuginfo. +* `n`, `no`, `off` or `false`: do not collapse code locations in debuginfo. +* `external`: collapse code locations in debuginfo only if the macro comes from a different crate. + ## control-flow-guard This flag controls whether LLVM enables the Windows [Control Flow diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index bbd81e7437c67..32dc992c42fac 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -348,11 +348,7 @@ $ llvm-cov report \ ## `-Z coverage-options=` -This unstable option provides finer control over some aspects of coverage -instrumentation. Pass one or more of the following values, separated by commas. - -- Either `no-branch`, `branch` or `mcdc` - - `branch` enables branch coverage instrumentation and `mcdc` further enables modified condition/decision coverage instrumentation. `no-branch` disables branch coverage instrumentation, which is same as do not pass `branch` or `mcdc`. +[This unstable option is described in the Unstable Book.](../unstable-book/compiler-flags/coverage-options.html) ## Other references diff --git a/src/doc/rustc/src/jobserver.md b/src/doc/rustc/src/jobserver.md new file mode 100644 index 0000000000000..da82b0df7c629 --- /dev/null +++ b/src/doc/rustc/src/jobserver.md @@ -0,0 +1,86 @@ +# Jobserver + +Internally, `rustc` may take advantage of parallelism. `rustc` will coordinate +with the build system calling it if a [GNU Make jobserver] is passed in the +`MAKEFLAGS` environment variable. Other flags may have an effect as well, such +as [`CARGO_MAKEFLAGS`]. If a jobserver is not passed, then `rustc` will choose +the number of jobs to use. + +Starting with Rust 1.76.0, `rustc` will warn if a jobserver appears to be +available but is not accessible, e.g.: + +```console +$ echo 'fn main() {}' | MAKEFLAGS=--jobserver-auth=3,4 rustc - +warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=3,4"`: cannot open file descriptor 3 from the jobserver environment variable value: Bad file descriptor (os error 9) + | + = note: the build environment is likely misconfigured +``` + +## Integration with build systems + +The following subsections contain recommendations on how to integrate `rustc` +with build systems so that the jobserver is handled appropriately. + +### GNU Make + +When calling `rustc` from GNU Make, it is recommended that all `rustc` +invocations are marked as recursive in the `Makefile` (by prefixing the command +line with the `+` indicator), so that GNU Make enables the jobserver for them. +For instance: + + + +```make +x: + +@echo 'fn main() {}' | rustc - +``` + +In particular, GNU Make 4.3 (a widely used version as of 2024) passes a simple +pipe jobserver in `MAKEFLAGS` even when it was not made available for the child +process, which in turn means `rustc` will warn about it. For instance, if the +`+` indicator is removed from the example above and GNU Make is called with e.g. +`make -j2`, then the aforementioned warning will trigger. + +For calls to `rustc` inside `$(shell ...)` inside a recursive Make, one can +disable the jobserver manually by clearing the `MAKEFLAGS` variable, e.g.: + +```make +S := $(shell MAKEFLAGS= rustc --print sysroot) + +x: + @$(MAKE) y + +y: + @echo $(S) +``` + +### CMake + +CMake 3.28 supports the `JOB_SERVER_AWARE` option in its [`add_custom_target`] +command, e.g.: + +```cmake +cmake_minimum_required(VERSION 3.28) +project(x) +add_custom_target(x + JOB_SERVER_AWARE TRUE + COMMAND echo 'fn main() {}' | rustc - +) +``` + +For earlier versions, when using CMake with the Makefile generator, one +workaround is to have [`$(MAKE)`] somewhere in the command so that GNU Make +treats it as a recursive Make call, e.g.: + +```cmake +cmake_minimum_required(VERSION 3.22) +project(x) +add_custom_target(x + COMMAND DUMMY_VARIABLE=$(MAKE) echo 'fn main() {}' | rustc - +) +``` + +[GNU Make jobserver]: https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html +[`CARGO_MAKEFLAGS`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html +[`add_custom_target`]: https://cmake.org/cmake/help/latest/command/add_custom_target.html +[`$(MAKE)`]: https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 2578b71a158be..764798a80e6d2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -89,9 +89,9 @@ target | notes `aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+) `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 -`arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17) -`arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) +`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) +`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) @@ -143,21 +143,21 @@ target | std | notes `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat `aarch64-unknown-none` | * | Bare ARM64, hardfloat [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI -[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android -`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with musl 1.2.3 -`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with musl 1.2.3, hardfloat -[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian -[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian, hardfloat -`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23) -`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with musl 1.2.3 -[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android -`armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with musl 1.2.3 -`armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with musl 1.2.3, hardfloat -[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | ARMv7-A OpenHarmony -[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-A -[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R -[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, hardfloat +[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android +`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3 +`arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat +[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian +[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat +`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) +`armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 +[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android +`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27) +`armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 +`armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat +[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony +[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A +[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R +[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87] @@ -178,15 +178,15 @@ target | std | notes `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) `sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos -[`thumbv6m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv6-M -[`thumbv7em-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7E-M -[`thumbv7em-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMV7E-M, hardfloat -[`thumbv7m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-M -[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23) -[`thumbv8m.base-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Baseline -[`thumbv8m.main-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline -[`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat +[`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M +[`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M +[`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat +[`thumbv7m-none-eabi`](platform-support/thumbv7m-none-eabi.md) | * | Bare Armv7-M +[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode Armv7-A Android with NEON +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4, glibc 2.23) +[`thumbv8m.base-none-eabi`](platform-support/thumbv8m.base-none-eabi.md) | * | Bare Armv8-M Baseline +[`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline +[`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename]) @@ -264,27 +264,27 @@ target | std | host | notes `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) -[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers -[`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). -[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Bare ARMv4T -`armv4t-unknown-linux-gnueabi` | ? | | ARMv4T Linux -[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE -`armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc -`armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD -[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float -[`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) -[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) -[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7-A Linux with uClibc, softfloat -[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7-A Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7-A FreeBSD -[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7-A NetBSD w/hard-float -`armv7-wrs-vxworks-eabihf` | ? | | ARMv7-A for VxWorks +[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Arm Apple WatchOS 64-bit with 32-bit pointers +[`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). +[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Bare Armv4T +`armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux +[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE +`armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc +`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD +[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float +[`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain) +[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) +[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat +[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat +`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD +[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float +`armv7-wrs-vxworks-eabihf` | ? | | Armv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat -[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare ARMv7-A, hardfloat -[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS -`armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS -[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare ARMv8-R, hardfloat +[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare Armv7-A, hardfloat +[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Armv7-A Apple WatchOS +`armv7s-apple-ios` | ✓ | | Armv7-A Apple-A6 Apple iOS +[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) @@ -360,11 +360,11 @@ target | std | host | notes [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 -[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare ARMv4T -[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE +[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare Armv4T +[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare Armv5TE `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | -`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, musl 1.2.3 +`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3 [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | | WebAssembly [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index 6335a6405a102..0b1b10e4762e7 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -1,25 +1,131 @@ # `{arm,thumb}*-none-eabi(hf)?` -**Tier: 2** -- [arm(eb)?v7r-none-eabi(hf)?](armv7r-none-eabi.md) -- armv7a-none-eabi -- thumbv6m-none-eabi -- thumbv7m-none-eabi -- thumbv7em-none-eabi(hf)? -- thumbv8m.base-none-eabi -- thumbv8m.main-none-eabi(hf)? - -**Tier: 3** -- [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md) -- [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md) -- armv7a-none-eabihf -- [armv8r-none-eabihf](armv8r-none-eabihf.md) - -Bare-metal target for 32-bit ARM CPUs. - -If a target has a `*hf` variant, that variant uses the hardware floating-point -ABI and enables some minimum set of floating-point features based on the FPU(s) -available in that processor family. +## Tier 2 Target List + +- Arm A-Profile Architectures + - `armv7a-none-eabi` +- Arm R-Profile Architectures + - [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md) + - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armv7r-none-eabi.md) +- Arm M-Profile Architectures + - [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md) + - [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md) + - [`thumbv7em-none-eabi` and `thumbv7em-none-eabihf`](thumbv7em-none-eabi.md) + - [`thumbv8m.base-none-eabi`](thumbv8m.base-none-eabi.md) + - [`thumbv8m.main-none-eabi` and `thumbv8m.main-none-eabihf`](thumbv8m.main-none-eabi.md) +- *Legacy* Arm Architectures + - None + +## Tier 3 Target List + +- Arm A-Profile Architectures + - `armv7a-none-eabihf` +- Arm R-Profile Architectures + - [`armv8r-none-eabihf`](armv8r-none-eabihf.md) +- Arm M-Profile Architectures + - None +- *Legacy* Arm Architectures + - [`armv4t-none-eabi` and `thumbv4t-none-eabi`](armv4t-none-eabi.md) + - [`armv5te-none-eabi` and `thumbv5te-none-eabi`](armv5te-none-eabi.md) + +## Common Target Details + +This documentation covers details that apply to a range of bare-metal targets +for 32-bit Arm CPUs. In addition, target specific details may be covered in +their own document. + +There are two 32-bit instruction set architectures (ISAs) defined by Arm: + +- The [*A32 ISA*][a32-isa], with fixed-width 32-bit instructions. Previously + known as the *Arm* ISA, this originated with the original ARM1 of 1985 and has + been updated by various revisions to the architecture specifications ever + since. +- The [*T32 ISA*][t32-isa], with a mix of 16-bit and 32-bit width instructions. + Note that this term includes both the original 16-bit width *Thumb* ISA + introduced with the Armv4T architecture in 1994, and the later 16/32-bit sized + *Thumb-2* ISA introduced with the Armv6T2 architecture in 2003. Again, these + ISAs have been revised by subsequent revisions to the relevant Arm + architecture specifications. + +There is also a 64-bit ISA with fixed-width 32-bit instructions called the *A64 +ISA*, but targets which implement that instruction set generally start with +`aarch64*` and are discussed elsewhere. + +Rust targets starting with `arm*` generate Arm (A32) code by default, whilst +targets named `thumb*` generate Thumb (T32) code by default. Most Arm chips +support both Thumb mode and Arm mode, with the notable exception that M-profile +processors (`thumbv*m*-none-eabi*` targets) *only* support Thumb-mode. + +Rust targets ending with `eabi` use the so-called *soft-float ABI*: functions +which take `f32` or `f64` as arguments will have those values packed into +integer registers. This means that an FPU is not required from an ABI +perspective, but within a function floating-point instructions may still be used +if the code is compiled with a `target-cpu` or `target-feature` option that +enables FPU support. + +Rust targets ending in `eabihf` use the so-called *hard-float ABI*: functions +which take `f32` or `f64` as arguments will have them passed via FPU registers. +These targets therefore require the availability of an FPU and will assume some +baseline level of floating-point support is available (which can vary depending +on the target). More advanced floating-point instructions may be generated if +the code is compiled with a `target-cpu` or `target-feature` option that enables +such additional FPU support. For example, if a given hard-float target has +baseline *single-precision* (`f32`) support in hardware, there may be +`target-cpu` or `target-feature` options that tell LLVM to assume your processor +in fact also has *double-precision* (`f64`) support. + +You may of course use the `f32` and `f64` types in your code, regardless of the +ABI being used, or the level of support your processor has for performing such +operations in hardware. Any floating-point operations that LLVM assumes your +processor cannot support will be lowered to library calls (like `__aeabi_dadd`) +which perform the floating-point operation in software using integer +instructions. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[a32-isa]: https://developer.arm.com/Architectures/A32%20Instruction%20Set%20Architecture + +## Target CPU and Target Feature options + +It is possible to tell Rust (or LLVM) that you have a specific model of Arm +processor, using the [`-C target-cpu`][target-cpu] option. You can also control +whether Rust (or LLVM) will include instructions that target optional hardware +features, e.g. hardware floating-point, or Advanced SIMD operations, using [`-C +target-feature`][target-feature]. + +It is important to note that selecting a *target-cpu* will typically enable +*all* the optional features available from Arm on that model of CPU and your +particular implementation of that CPU may not have those features available. In +that case, you can use `-C target-feature=-option` to turn off the specific CPU +features you do not have available, leaving you with the optimized instruction +scheduling and support for the features you do have. More details are available +in the detailed target-specific documentation. + +**Note:** Many target-features are currently unstable and subject to change, and +if you use them you should disassemble the compiler output and manually inspect +it to ensure only appropriate instructions for your CPU have been generated. + +If you wish to use the *target-cpu* and *target-feature* options, you can add +them to your `.cargo/config.toml` file alongside any other flags your project +uses (likely linker related ones): + +```toml +rustflags = [ + # Usual Arm bare-metal linker setup + "-Clink-arg=-Tlink.x", + "-Clink-arg=--nmagic", + # tell Rust we have a Cortex-M55 + "-Ctarget-cpu=cortex-m55", + # tell Rust our Cortex-M55 doesn't have Floating-Point M-Profile Vector + # Extensions (but it does have everything else a Cortex-M55 could have). + "-Ctarget-feature=-mve.fp" +] + +[build] +target = "thumbv8m.main-none-eabihf" +``` + +[target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu +[target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature ## Requirements @@ -45,14 +151,11 @@ according to the specific device you are using. Pass `-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use `your_script.ld` during linking. -Targets named `thumb*` instead of `arm*` -generate Thumb-mode code by default. M-profile processors (`thumbv*m*-*` -targets) only support Thumb-mode code. -For the `arm*` targets, Thumb-mode code generation can be enabled by using -`-C target-feature=+thumb-mode`. Using the unstable -`#![feature(arm_target_feature)]`, the attribute -`#[target_feature(enable = "thumb-mode")]` can be applied to individual -`unsafe` functions to cause those functions to be compiled to Thumb-mode code. +For the `arm*` targets, Thumb-mode code generation can be enabled by using `-C +target-feature=+thumb-mode`. Using the unstable +`#![feature(arm_target_feature)]`, the attribute `#[target_feature(enable = +"thumb-mode")]` can be applied to individual `unsafe` functions to cause those +functions to be compiled to Thumb-mode code. ## Building Rust Programs @@ -69,16 +172,27 @@ build-std = ["core"] ``` Most of `core` should work as expected, with the following notes: -* If the target is not `*hf`, then floating-point operations are emulated in - software. + +* Floating-point operations are emulated in software unless LLVM is told to + enable FPU support (either by using an `eabihf` target, specifying a + `target-cpu` with FPU support, or using a `target-feature` to support for a + specific kind of FPU) * Integer division is also emulated in software on some targets, depending on - the CPU. -* Architectures prior to ARMv7 don't have atomic instructions. + the target, `target-cpu` and `target-feature`s. +* Older Arm architectures (e.g. Armv4, Armv5TE and Armv6-M) are limited to basic + [`load`][atomic-load] and [`store`][atomic-store] operations, and not more + advanced operations like [`fetch_add`][fetch-add] or + [`compare_exchange`][compare-exchange]. `alloc` is also supported, as long as you provide your own global allocator. Rust programs are output as ELF files. +[atomic-load]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.load +[atomic-store]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.store +[fetch-add]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.fetch_add +[compare-exchange]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.compare_exchange + ## Testing This is a cross-compiled target that you will need to emulate during testing. diff --git a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md index 9fd0ac4988162..2e82753586261 100644 --- a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md +++ b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md @@ -73,7 +73,7 @@ Tests can be run on AArch64 Windows 11 devices. ## Cross-compilation toolchains and C code -C code can be built using the Arm64-targetting MSVC or Clang toolchain. +C code can be built using the Arm64-targeting MSVC or Clang toolchain. To compile: diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md index 32d3440f1dc98..e7e3fd01c4dc7 100644 --- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md @@ -1,22 +1,22 @@ # armeb-unknown-linux-gnueabi **Tier: 3** -Target for cross-compiling Linux user-mode applications targeting the ARM BE8 architecture. +Target for cross-compiling Linux user-mode applications targeting the Arm BE8 architecture. ## Overview -BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian ARM systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). +BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian Arm systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). ## History -BE8 architecture is the default big-endian architecture for ARM since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). It's predecessor, used for ARMv4 and ARMv5 devices was [BE32](https://developer.arm.com/documentation/dui0474/j/linker-command-line-options/--be32). On ARMv6 architecture, endianness can be configured via [system registers](https://developer.arm.com/documentation/ddi0290/g/unaligned-and-mixed-endian-data-access-support/mixed-endian-access-support/interaction-between-the-bus-protocol-and-the-core-endianness). However, BE32 was withdrawn for [ARMv7](https://developer.arm.com/documentation/ddi0406/cb/Appendixes/Deprecated-and-Obsolete-Features/Obsolete-features/Support-for-BE-32-endianness-model) onwards. +BE8 architecture is the default big-endian architecture for Arm since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). It's predecessor, used for Armv4 and Armv5 devices was [BE32](https://developer.arm.com/documentation/dui0474/j/linker-command-line-options/--be32). On Armv6 architecture, endianness can be configured via [system registers](https://developer.arm.com/documentation/ddi0290/g/unaligned-and-mixed-endian-data-access-support/mixed-endian-access-support/interaction-between-the-bus-protocol-and-the-core-endianness). However, BE32 was withdrawn for [Armv7](https://developer.arm.com/documentation/ddi0406/cb/Appendixes/Deprecated-and-Obsolete-Features/Obsolete-features/Support-for-BE-32-endianness-model) onwards. ## Target Maintainers * [@WorksButNotTested](https://github.com/WorksButNotTested) ## Requirements -The target is cross-compiled. This target supports `std` in the normal way (indeed only nominal changes are required from the standard ARM configuration). +The target is cross-compiled. This target supports `std` in the normal way (indeed only nominal changes are required from the standard Arm configuration). ## Target definition -The target definition can be seen [here](https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs). In particular, it should be noted that the `features` specify that this target is built for the ARMv8 core. Though this can likely be modified as required. +The target definition can be seen [here](https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs). In particular, it should be noted that the `features` specify that this target is built for the Armv8 core. Though this can likely be modified as required. ## Building the target Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index 29c47db8351c7..f4c8dd46f1d03 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -2,12 +2,12 @@ Tier 3 -Bare-metal target for any cpu in the ARMv4T architecture family, supporting -ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code +Bare-metal target for any cpu in the Armv4T architecture family, supporting +ARM/Thumb code interworking (aka `A32`/`T32`), with ARM code as the default code generation. In particular this supports the Game Boy Advance (GBA), but there's nothing -GBA-specific with this target, so any ARMv4T device should work fine. +GBA-specific with this target, so any Armv4T device should work fine. See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all `arm-none-eabi` targets. diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md index 37284ba720997..41621e070bb48 100644 --- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -2,11 +2,11 @@ **Tier: 3** -Bare-metal target for any cpu in the ARMv5TE architecture family, supporting -ARM/Thumb code interworking (aka `a32`/`t32`), with `a32` code as the default code +Bare-metal target for any cpu in the Armv5TE architecture family, supporting +ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code generation. -The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `t32`. +The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `T32`. See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all `arm-none-eabi` targets. diff --git a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md index 540e5a4af938e..160986aeae94f 100644 --- a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md +++ b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md @@ -2,7 +2,7 @@ **Tier: 3** -The Nintendo 3DS platform, which has an ARMv6K processor, and its associated +The Nintendo 3DS platform, which has an Armv6k processor, and its associated operating system (`horizon`). Rust support for this target is not affiliated with Nintendo, and is not derived diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md index e351ea0013003..f22a20835c1af 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md @@ -2,7 +2,7 @@ **Tier: 3** -This target supports ARMv7 softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U). +This target supports Armv7-A softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U). ## Target maintainers @@ -16,7 +16,7 @@ This target supports host tools and std. ## Building the target -You will need to download or build a `'C'` cross toolchain that targets ARMv7 softfloat and that uses the uclibc-ng standard library. If your target hardware is something like a router or an embedded device, keep in mind that manufacturer supplied SDKs for this class of CPU could be outdated and potentially unsuitable for bootstrapping rust. +You will need to download or build a `'C'` cross toolchain that targets Armv7-A softfloat and that uses the uclibc-ng standard library. If your target hardware is something like a router or an embedded device, keep in mind that manufacturer supplied SDKs for this class of CPU could be outdated and potentially unsuitable for bootstrapping rust. [Here](https://github.com/lancethepants/tomatoware-toolchain) is a sample toolchain that is built using [buildroot](https://buildroot.org/). It uses modern toolchain components, older thus universal kernel headers (2.6.36.4), and is used for a project called [Tomatoware](https://github.com/lancethepants/tomatoware). This toolchain is patched so that its sysroot is located at /mmc (e.g., /mmc/bin, /mmc/lib, /mmc/include). This is useful in scenarios where the root filesystem is read-only but you are able attach external storage loaded with user applications. Tomatoware is an example of this that even allows you to run various compilers and developer tools natively on the target device. @@ -46,7 +46,7 @@ The following assumes you are using the Tomatoware toolchain and environment. Ad ### Native compilation -Since this target supports host tools, you can natively build rust applications directly on your target device. This can be convenient because it removes the complexities of cross compiling and you can immediately test and deploy your binaries. One downside is that compiling on your ARMv7 CPU will probably be much slower than cross compilation on your x86 machine. +Since this target supports host tools, you can natively build rust applications directly on your target device. This can be convenient because it removes the complexities of cross compiling and you can immediately test and deploy your binaries. One downside is that compiling on your Armv7-A CPU will probably be much slower than cross compilation on your x86 machine. To setup native compilation: diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 1f029406367a2..1c8acc09c7746 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -2,7 +2,7 @@ **Tier: 3** -This tier supports the ARMv7 processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library. +This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library. ## Designated Developers diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index 670cead9e006b..5f0dc6a7115b9 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -2,7 +2,7 @@ **Tier: 2** -Bare-metal target for CPUs in the ARMv7-R architecture family, supporting +Bare-metal target for CPUs in the Armv7-R architecture family, supporting dual ARM/Thumb mode, with ARM mode as the default. Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r]. diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 588e5d7c99449..6f80a06020ff7 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -2,7 +2,7 @@ **Tier: 3** -Bare-metal target for CPUs in the ARMv8-R architecture family, supporting +Bare-metal target for CPUs in the Armv8-R architecture family, supporting dual ARM/Thumb mode, with ARM mode as the default. Processors in this family include the Arm [Cortex-R52][cortex-r52] diff --git a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md new file mode 100644 index 0000000000000..f4ed6201bbdc9 --- /dev/null +++ b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md @@ -0,0 +1,62 @@ +# `thumbv6m-none-eabi` + +**Tier: 2** + +Bare-metal target for CPUs in the [Armv6-M] architecture family, supporting a +subset of the [T32 ISA][t32-isa]. + +Processors in this family include the: + +* [Arm Cortex-M0][cortex-m0] +* [Arm Cortex-M0+][cortex-m0plus] +* [Arm Cortex-M1][cortex-m1] + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +This target uses the soft-float ABI: functions which take `f32` or `f64` as +arguments will have those values packed into integer registers. This is the +only option because there is no FPU support in [Armv6-M]. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[Armv6-M]: https://developer.arm.com/documentation/ddi0419/latest/ +[cortex-m0]: https://developer.arm.com/Processors/Cortex-M0 +[cortex-m0plus]: https://developer.arm.com/Processors/Cortex-M0+ +[cortex-m1]: https://developer.arm.com/Processors/Cortex-M1 + +## Target maintainers + +* [Rust Embedded Devices Working Group Cortex-M + Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` + +## Target CPU and Target Feature options + +See [the bare-metal Arm +docs](arm-none-eabi.md#target-cpu-and-target-feature-options) for details on how +to use these flags. + +### Table of supported CPUs + +| CPU | FPU | Target CPU | Target Features | +| ---------- | --- | --------------- | --------------------- | +| Cortex-M0 | No | `cortex-m0` | None | +| Cortex-M0+ | No | `cortex-m0plus` | None | +| Cortex-M1 | No | `cortex-m1` | None | + +### Arm Cortex-M0 + +The target CPU option is `cortex-m0`. + +There are no relevant feature flags, and the FPU is not available. + +### Arm Cortex-M0+ + +The target CPU option is `cortex-m0plus`. + +There are no relevant feature flags, and the FPU is not available. + +### Arm Cortex-M1 + +The target CPU option is `cortex-m1`. + +There are no relevant feature flags, and the FPU is not available. diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md new file mode 100644 index 0000000000000..f25ef0383b185 --- /dev/null +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -0,0 +1,74 @@ +# `thumbv7em-none-eabi` and `thumbv7em-none-eabihf` + +**Tier: 2** + +Bare-metal target for CPUs in the [Armv7E-M] architecture family, supporting a +subset of the [T32 ISA][t32-isa]. + +Processors in this family include the: + +* [Arm Cortex-M4][cortex-m4] and Arm Cortex-M4F +* [Arm Cortex-M7][cortex-m7] and Arm Cortex-M7F + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets, in particular the difference between the `eabi` and +`eabihf` ABI. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[Armv7E-M]: https://developer.arm.com/documentation/ddi0403/latest/ +[cortex-m4]: https://developer.arm.com/Processors/Cortex-M4 +[cortex-m7]: https://developer.arm.com/Processors/Cortex-M7 + +## Target maintainers + +* [Rust Embedded Devices Working Group Cortex-M + Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` + +## Target CPU and Target Feature options + +See [the bare-metal Arm +docs](arm-none-eabi.md#target-cpu-and-target-feature-options) for details on how +to use these flags. + +### Table of supported CPUs for `thumbv7em-none-eabi` + +| CPU | FPU | DSP | Target CPU | Target Features | +| ---------- | --- | --- | ----------- | --------------- | +| Any | No | Yes | None | None | +| Cortex-M4 | No | Yes | `cortex-m4` | `+soft-float` | +| Cortex-M4F | SP | Yes | `cortex-m4` | None | +| Cortex-M7 | No | Yes | `cortex-m7` | `+soft-float` | +| Cortex-M7F | SP | Yes | `cortex-m7` | `-fp64` | +| Cortex-M7F | DP | Yes | `cortex-m7` | None | + +### Table of supported CPUs for `thumbv7em-none-eabihf` + +| CPU | FPU | DSP | Target CPU | Target Features | +| ---------- | --- | --- | ----------- | --------------- | +| Any | SP | Yes | None | None | +| Cortex-M4F | SP | Yes | `cortex-m4` | None | +| Cortex-M7F | SP | Yes | `cortex-m7` | `-fp64` | +| Cortex-M7F | DP | Yes | `cortex-m7` | None | + +### Arm Cortex-M4 and Arm Cortex-M4F + +The target CPU is `cortex-m4`. + +* All Cortex-M4 have DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target* +* Cortex-M4F has a single precision FPU + * support is enabled by default with this *target-cpu* + * disable support using the `+soft-float` feature (`eabi` only) + +### Arm Cortex-M7 and Arm Cortex-M7F + +The target CPU is `cortex-m7`. + +* All Cortex-M7 have DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target* +* Cortex-M7F have either a single-precision or double-precision FPU + * double-precision support is enabled by default with this *target-cpu* + * opt-out by using the `-f64` *target-feature* + * disable support entirely using the `+soft-float` feature (`eabi` only) diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md new file mode 100644 index 0000000000000..b258033bb0fa7 --- /dev/null +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -0,0 +1,44 @@ +# `thumbv7m-none-eabi` + +**Tier: 2** + +Bare-metal target for CPUs in the [Armv7-M] architecture family, supporting a +subset of the [T32 ISA][t32-isa]. + +Processors in this family include the: + +* [Arm Cortex-M3][cortex-m3] + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +This target uses the soft-float ABI: functions which take `f32` or `f64` as +arguments will have those values packed into integer registers. This is the +only option because there is no FPU support in [Armv7-M]. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[Armv7-M]: https://developer.arm.com/documentation/ddi0403/latest/ +[cortex-m3]: https://developer.arm.com/Processors/Cortex-M3 + +## Target maintainers + +* [Rust Embedded Devices Working Group Cortex-M + Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` + +## Target CPU and Target Feature options + +See [the bare-metal Arm +docs](arm-none-eabi.md#target-cpu-and-target-feature-options) for details on how +to use these flags. + +### Table of supported CPUs + +| CPU | FPU | Target CPU | Target Features | +| ---------- | --- | ----------- | --------------------- | +| Cortex-M3 | No | `cortex-m3` | None | + +### Arm Cortex-M3 + +The target CPU option is `cortex-m3`. + +There are no relevant feature flags, and the FPU is not available. diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md new file mode 100644 index 0000000000000..0ae4e3e94bd8c --- /dev/null +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -0,0 +1,44 @@ +# `thumbv8m.base-none-eabi` + +**Tier: 2** + +Bare-metal target for CPUs in the Baseline [Armv8-M] architecture family, +supporting a subset of the [T32 ISA][t32-isa]. + +Processors in this family include the: + +* [Arm Cortex-M23][cortex-m23] + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +This target uses the soft-float ABI: functions which take `f32` or `f64` as +arguments will have those values packed into integer registers. This is the +only option because there is no FPU support in [Armv8-M] Baseline. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[Armv8-M]: https://developer.arm.com/documentation/ddi0553/latest/ +[cortex-m23]: https://developer.arm.com/Processors/Cortex-M23 + +## Target maintainers + +* [Rust Embedded Devices Working Group Cortex-M + Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` + +## Target CPU and Target Feature options + +See [the bare-metal Arm +docs](arm-none-eabi.md#target-cpu-and-target-feature-options) for details on how +to use these flags. + +### Table of supported CPUs + +| CPU | FPU | Target CPU | Target Features | +| ----------- | --- | ------------ | --------------------- | +| Cortex-M23 | No | `cortex-m23` | None | + +### Arm Cortex-M23 + +The target CPU option is `cortex-m23`. + +There are no relevant feature flags, and the FPU is not available. diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md new file mode 100644 index 0000000000000..4e696f9c30461 --- /dev/null +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -0,0 +1,135 @@ +# `thumbv8m.main-none-eabi` and `thumbv8m.main-none-eabihf` + +**Tier: 2** + +Bare-metal target for CPUs in the Mainline [Armv8-M] architecture family, +supporting a subset of the [T32 ISA][t32-isa]. + +Processors in this family include the: + +* [Arm Cortex-M33][cortex-m33] +* [Arm Cortex-M35P][cortex-m35p] +* [Arm Cortex-M55][cortex-m55] +* [Arm Cortex-M85][cortex-m85] + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets, in particular the difference between the `eabi` and +`eabihf` ABI. + +[t32-isa]: https://developer.arm.com/Architectures/T32%20Instruction%20Set%20Architecture +[Armv8-M]: https://developer.arm.com/documentation/ddi0553/latest/ +[cortex-m33]: https://developer.arm.com/Processors/Cortex-M33 +[cortex-m35p]: https://developer.arm.com/Processors/Cortex-M35P +[cortex-m55]: https://developer.arm.com/Processors/Cortex-M55 +[cortex-m85]: https://developer.arm.com/Processors/Cortex-M85 + +## Target maintainers + +* [Rust Embedded Devices Working Group Cortex-M + Team](https://github.com/rust-embedded), `cortex-m@teams.rust-embedded.org` + +## Target CPU and Target Feature options + +See [the bare-metal Arm +docs](arm-none-eabi.md#target-cpu-and-target-feature-options) for details on how +to use these flags. + +### Table of supported CPUs for `thumbv8m.main-none-eabi` + +| CPU | FPU | DSP | MVE | Target CPU | Target Features | +| ----------- | --- | --- | --------- | ------------- | --------------------- | +| Unspecified | No | No | No | None | None | +| Cortex-M33 | No | No | No | `cortex-m33` | `+soft-float,-dsp` | +| Cortex-M33 | No | Yes | No | `cortex-m33` | `+soft-float` | +| Cortex-M33 | SP | No | No | `cortex-m33` | `-dsp` | +| Cortex-M33 | SP | Yes | No | `cortex-m33` | None | +| Cortex-M35P | No | No | No | `cortex-m35p` | `+soft-float,-dsp` | +| Cortex-M35P | No | Yes | No | `cortex-m35p` | `+soft-float` | +| Cortex-M35P | SP | No | No | `cortex-m35p` | `-dsp` | +| Cortex-M35P | SP | Yes | No | `cortex-m35p` | None | +| Cortex-M55 | No | Yes | No | `cortex-m55` | `+soft-float,-mve` | +| Cortex-M55 | DP | Yes | No | `cortex-m55` | `-mve` | +| Cortex-M55 | No | Yes | Int | `cortex-m55` | `+soft-float,-mve.fp` | +| Cortex-M55 | DP | Yes | Int | `cortex-m55` | `-mve.fp` | +| Cortex-M55 | DP | Yes | Int+Float | `cortex-m55` | None | +| Cortex-M85 | No | Yes | No | `cortex-m85` | `+soft-float,-mve` | +| Cortex-M85 | DP | Yes | No | `cortex-m85` | `-mve` | +| Cortex-M85 | No | Yes | Int | `cortex-m85` | `+soft-float,-mve.fp` | +| Cortex-M85 | DP | Yes | Int | `cortex-m85` | `-mve.fp` | +| Cortex-M85 | DP | Yes | Int+Float | `cortex-m85` | None | + +### Table of supported CPUs for `thumbv8m.main-none-eabihf` + +| CPU | FPU | DSP | MVE | Target CPU | Target Features | +| ----------- | --- | --- | --------- | ------------- | --------------------- | +| Unspecified | SP | No | No | None | None | +| Cortex-M33 | SP | No | No | `cortex-m33` | `-dsp` | +| Cortex-M33 | SP | Yes | No | `cortex-m33` | None | +| Cortex-M33P | SP | No | No | `cortex-m35p` | `-dsp` | +| Cortex-M33P | SP | Yes | No | `cortex-m35p` | None | +| Cortex-M55 | DP | Yes | No | `cortex-m55` | `-mve` | +| Cortex-M55 | DP | Yes | Int | `cortex-m55` | `-mve.fp` | +| Cortex-M55 | DP | Yes | Int+Float | `cortex-m55` | None | +| Cortex-M85 | DP | Yes | No | `cortex-m85` | `-mve` | +| Cortex-M85 | DP | Yes | Int | `cortex-m85` | `-mve.fp` | +| Cortex-M85 | DP | Yes | Int+Float | `cortex-m85` | None | + +### Arm Cortex-M33 + +The target CPU is `cortex-m33`. + +* Has optional DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target-cpu* +* Has an optional single precision FPU + * support is enabled by default with this *target-cpu* + * disable support using the `+soft-float` feature (`eabi` only) + +### Arm Cortex-M35P + +The target CPU is `cortex-m35p`. + +* Has optional DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target-cpu* +* Has an optional single precision FPU + * support is enabled by default with this *target-cpu* + * disable support using the `+soft-float` feature (`eabi` only) + +### Arm Cortex-M55 + +The target CPU is `cortex-m55`. + +* Has DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target-cpu* +* Has an optional double-precision FPU that also supports half-precision FP16 + values + * support is enabled by default with this *target-cpu* + * disable support using the `+soft-float` feature (`eabi` only) +* Has optional support for M-Profile Vector Extensions + * Also known as *Helium Technology* + * Available with only integer support, or both integer/float support + * The appropriate feature for the MVE is either `mve` (integer) or `mve.fp` + (float) + * `mve.fp` is enabled by default on this target CPU + * disable using `-mve.fp` (disable float MVE) or `-mve` (disable all MVE) + +### Arm Cortex-M85 + +The target CPU is `cortex-m85`. + +* Has DSP extensions + * support is controlled by the `dsp` *target-feature* + * enabled by default with this *target-cpu* +* Has an optional double-precision FPU that also supports half-precision FP16 + values + * support is enabled by default with this *target-cpu* + * disable support using the `+soft-float` feature (`eabi` only) +* Has optional support for M-Profile Vector Extensions + * Also known as *Helium Technology* + * Available with only integer support, or both integer/float support + * The appropriate feature for the MVE is either `mve` (integer) or `mve.fp` + (float) + * `mve.fp` is enabled by default on this target CPU + * disable using `-mve.fp` (disable float MVE) or `-mve` (disable all MVE) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index 77efa9c328211..4faa198873536 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -59,7 +59,7 @@ languages compiled to WebAssembly, for example C/C++. Any ABI differences or mismatches are considered bugs that need to be fixed. By default the WASI targets in Rust ship in rustup with a precompiled copy of -[`wasi-libc`] meaning that a WebAssembly-targetting-Clang is not required to +[`wasi-libc`] meaning that a WebAssembly-targeting-Clang is not required to use the WASI targets from Rust. If there is no actual interoperation with C then `rustup target add wasm32-wasip1` is all that's needed to get started with WASI. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 7d573ac950d8e..c05077befdb3a 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -417,7 +417,7 @@ warning: 1 warning emitted This lint is **warn-by-default**. It detects explicit links that are the same as computed automatic links. -This usually means the explicit links are removeable. For example: +This usually means the explicit links are removable. For example: ```rust #![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default. diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 56c14b1638a6f..1a367b8274b96 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -168,4 +168,4 @@ render differently in this case: ``` `1.` and `2.` will be displayed as is in the rendered documentation (ie, `[a]` and `[b][c]`) -whereas `3.` and `4.` will be replaced by a link targetting `e` for `[d](e)` and `g` for `[f]`. +whereas `3.` and `4.` will be replaced by a link targeting `e` for `[d](e)` and `g` for `[f]`. diff --git a/src/doc/unstable-book/src/compiler-flags/coverage-options.md b/src/doc/unstable-book/src/compiler-flags/coverage-options.md index 5e192d9aca13e..2127883355025 100644 --- a/src/doc/unstable-book/src/compiler-flags/coverage-options.md +++ b/src/doc/unstable-book/src/compiler-flags/coverage-options.md @@ -5,4 +5,13 @@ This option controls details of the coverage instrumentation performed by Multiple options can be passed, separated by commas. Valid options are: -- `no-branch`, `branch` or `mcdc`: `branch` enables branch coverage instrumentation and `mcdc` further enables modified condition/decision coverage instrumentation. `no-branch` disables branch coverage instrumentation as well as mcdc instrumentation, which is same as do not pass `branch` or `mcdc`. +- `block`, `branch`, `mcdc`: + Sets the level of coverage instrumentation. + Setting the level will override any previously-specified level. + - `block` (default): + Blocks in the control-flow graph will be instrumented for coverage. + - `branch`: + In addition to block coverage, also enables branch coverage instrumentation. + - `mcdc`: + In addition to block and branch coverage, also enables MC/DC instrumentation. + (Branch coverage instrumentation may differ in some cases.) diff --git a/src/doc/unstable-book/src/language-features/coroutines.md b/src/doc/unstable-book/src/language-features/coroutines.md index f8e5a22fbd5c8..9fb07594650f4 100644 --- a/src/doc/unstable-book/src/language-features/coroutines.md +++ b/src/doc/unstable-book/src/language-features/coroutines.md @@ -26,13 +26,13 @@ tweaks to the overall design. A syntactical example of a coroutine is: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; @@ -48,7 +48,8 @@ fn main() { } ``` -Coroutines are closure-like literals which can contain a `yield` statement. The +Coroutines are closure-like literals which are annotated with `#[coroutine]` +and can contain a `yield` statement. The `yield` statement takes an optional expression of a value to yield out of the coroutine. All coroutine literals implement the `Coroutine` trait in the `std::ops` module. The `Coroutine` trait has one main method, `resume`, which @@ -58,13 +59,13 @@ An example of the control flow of coroutines is that the following example prints all numbers in order: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { println!("2"); yield; println!("4"); @@ -78,9 +79,9 @@ fn main() { } ``` -At this time the main intended use case of coroutines is an implementation -primitive for async/await syntax, but coroutines will likely be extended to -ergonomic implementations of iterators and other primitives in the future. +At this time the main use case of coroutines is an implementation +primitive for `async`/`await` and `gen` syntax, but coroutines +will likely be extended to other primitives in the future. Feedback on the design and usage is always appreciated! ### The `Coroutine` trait @@ -163,14 +164,14 @@ which point all state is saved off in the coroutine and a value is returned. Let's take a look at an example to see what's going on here: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let ret = "foo"; - let mut coroutine = move || { + let mut coroutine = #[coroutine] move || { yield 1; return ret }; @@ -183,7 +184,7 @@ fn main() { This coroutine literal will compile down to something similar to: ```rust -#![feature(arbitrary_self_types, coroutines, coroutine_trait)] +#![feature(arbitrary_self_types, coroutine_trait)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; diff --git a/src/doc/unstable-book/src/language-features/inline-const-pat.md b/src/doc/unstable-book/src/language-features/inline-const-pat.md index 5f0f7547a0a89..c6f54d79cfce8 100644 --- a/src/doc/unstable-book/src/language-features/inline-const-pat.md +++ b/src/doc/unstable-book/src/language-features/inline-const-pat.md @@ -2,8 +2,6 @@ The tracking issue for this feature is: [#76001] -See also [`inline_const`](inline-const.md) - ------ This feature allows you to use inline constant expressions in pattern position: diff --git a/src/doc/unstable-book/src/language-features/inline-const.md b/src/doc/unstable-book/src/language-features/inline-const.md deleted file mode 100644 index 7be70eed6cedc..0000000000000 --- a/src/doc/unstable-book/src/language-features/inline-const.md +++ /dev/null @@ -1,32 +0,0 @@ -# `inline_const` - -The tracking issue for this feature is: [#76001] - -See also [`inline_const_pat`](inline-const-pat.md) - ------- - -This feature allows you to use inline constant expressions. For example, you can -turn this code: - -```rust -# fn add_one(x: i32) -> i32 { x + 1 } -const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4; - -fn main() { - let x = add_one(MY_COMPUTATION); -} -``` - -into this code: - -```rust -#![feature(inline_const)] - -# fn add_one(x: i32) -> i32 { x + 1 } -fn main() { - let x = add_one(const { 1 + 2 * 3 / 4 }); -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md index 0f4fb405669a1..63134f7ae28c4 100644 --- a/src/doc/unstable-book/src/the-unstable-book.md +++ b/src/doc/unstable-book/src/the-unstable-book.md @@ -5,13 +5,13 @@ each one organized by a "feature flag." That is, when using an unstable feature of Rust, you must use a flag, like this: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 5ae27bc8c91c5..40a25f13fcbdd 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -47,6 +47,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "install" -d 'Install distribu complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained in this repository' complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' +complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies' complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f @@ -590,3 +591,39 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-genera complete -c x.py -n "__fish_seen_subcommand_from suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_seen_subcommand_from suggest" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip -d 'build paths to skip' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l set -d 'override options in config.toml' -r -f +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l versioned-dirs -d 'Always include version in subdir name' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_seen_subcommand_from vendor" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index d39639a1f91d8..f3d1d372c7337 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -74,6 +74,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') + [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') break } 'x.py;build' { @@ -724,6 +725,49 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } + 'x.py;vendor' { + [CompletionResult]::new('--sync', 'sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') + [CompletionResult]::new('--versioned-dirs', 'versioned-dirs', [CompletionResultType]::ParameterName, 'Always include version in subdir name') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--dump-bootstrap-shims', 'dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--bypass-bootstrap-lock', 'bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') + [CompletionResult]::new('--skip-stage0-validation', 'skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } }) $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 1f1a9a70767fa..82cacb52ffeef 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -57,6 +57,9 @@ _x.py() { bootstrap,test) cmd="bootstrap__test" ;; + bootstrap,vendor) + cmd="bootstrap__vendor" + ;; *) ;; esac @@ -64,7 +67,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1879,6 +1882,120 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + x.py__vendor) + opts="-v -i -j -h --sync --versioned-dirs --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --sync) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --skip) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --reproducible-artifact) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; esac } diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index b920309ac2c15..12e96dbd40a31 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -742,6 +742,51 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ && ret=0 +;; +(vendor) +_arguments "${_arguments_options[@]}" \ +'*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--versioned-dirs[Always include version in subdir name]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ +'--json-output[use message-format=json]' \ +'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'--skip-stage0-validation[Skip stage0 compiler validation]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 ;; esac ;; @@ -766,6 +811,7 @@ _x.py_commands() { 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ 'suggest:Suggest a subset of tests to run, based on modified files' \ +'vendor:Vendor dependencies' \ ) _describe -t commands 'x.py commands' commands "$@" } @@ -844,6 +890,11 @@ _x.py__test_commands() { local commands; commands=() _describe -t commands 'x.py test commands' commands "$@" } +(( $+functions[_x.py__vendor_commands] )) || +_x.py__vendor_commands() { + local commands; commands=() + _describe -t commands 'x.py vendor commands' commands "$@" +} if [ "$funcstack[1]" = "_x.py" ]; then _x.py "$@" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 9a23811ed3f97..31222f213d800 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,11 +10,9 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.12", default-features = false, features = ["config"] } base64 = "0.21.7" -byteorder = "1.5" itertools = "0.12" indexmap = "2" minifier = "0.3.0" -once_cell = "1.10.0" regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde_json = "1.0" diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index f078ad2fb5376..465f969435d1b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -635,7 +635,16 @@ impl Options { let libs = matches .opt_strs("L") .iter() - .map(|s| SearchPath::from_cli_opt(&sysroot, &target, early_dcx, s)) + .map(|s| { + SearchPath::from_cli_opt( + &sysroot, + &target, + early_dcx, + s, + #[allow(rustc::bad_opt_access)] // we have no `Session` here + unstable_opts.unstable_options, + ) + }) .collect(); let show_coverage = matches.opt_present("show-coverage"); diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 64f0e096cd02e..5c5651f3ef0e6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -35,13 +35,13 @@ use rustc_resolve::rustdoc::may_be_doc_link; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; -use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::Write; use std::iter::Peekable; use std::ops::{ControlFlow, Range}; use std::str::{self, CharIndices}; +use std::sync::OnceLock; use crate::clean::RenderedLink; use crate::doctest; @@ -1994,7 +1994,7 @@ pub struct IdMap { } // The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly. -static DEFAULT_ID_MAP: Lazy, usize>> = Lazy::new(|| init_id_map()); +static DEFAULT_ID_MAP: OnceLock, usize>> = OnceLock::new(); fn init_id_map() -> FxHashMap, usize> { let mut map = FxHashMap::default(); @@ -2051,7 +2051,7 @@ fn init_id_map() -> FxHashMap, usize> { impl IdMap { pub fn new() -> Self { - IdMap { map: DEFAULT_ID_MAP.clone() } + IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone() } } pub(crate) fn derive + ToString>(&mut self, candidate: S) -> String { diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs index 54407c614c4c7..8d715814faad7 100644 --- a/src/librustdoc/html/render/search_index/encode.rs +++ b/src/librustdoc/html/render/search_index/encode.rs @@ -166,13 +166,12 @@ pub(crate) fn write_bitmap_to_bytes( containers.push(container); } // https://github.com/RoaringBitmap/RoaringFormatSpec - use byteorder::{WriteBytesExt, LE}; const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346; const SERIAL_COOKIE: u32 = 12347; const NO_OFFSET_THRESHOLD: u32 = 4; let size: u32 = containers.len().try_into().unwrap(); let start_offset = if has_run { - out.write_u32::(SERIAL_COOKIE | ((size - 1) << 16))?; + out.write_all(&u32::to_le_bytes(SERIAL_COOKIE | ((size - 1) << 16)))?; for set in containers.chunks(8) { let mut b = 0; for (i, container) in set.iter().enumerate() { @@ -180,7 +179,7 @@ pub(crate) fn write_bitmap_to_bytes( b |= 1 << i; } } - out.write_u8(b)?; + out.write_all(&[b])?; } if size < NO_OFFSET_THRESHOLD { 4 + 4 * size + ((size + 7) / 8) @@ -188,21 +187,21 @@ pub(crate) fn write_bitmap_to_bytes( 4 + 8 * size + ((size + 7) / 8) } } else { - out.write_u32::(SERIAL_COOKIE_NO_RUNCONTAINER)?; - out.write_u32::(containers.len().try_into().unwrap())?; + out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?; + out.write_all(&u32::to_le_bytes(containers.len().try_into().unwrap()))?; 4 + 4 + 4 * size + 4 * size }; for (&key, container) in keys.iter().zip(&containers) { // descriptive header let key: u32 = key.into(); let count: u32 = container.popcount() - 1; - out.write_u32::((count << 16) | key)?; + out.write_all(&u32::to_le_bytes((count << 16) | key))?; } if !has_run || size >= NO_OFFSET_THRESHOLD { // offset header let mut starting_offset = start_offset; for container in &containers { - out.write_u32::(starting_offset)?; + out.write_all(&u32::to_le_bytes(starting_offset))?; starting_offset += match container { Container::Bits(_) => 8192u32, Container::Array(array) => u32::try_from(array.len()).unwrap() * 2, @@ -214,19 +213,19 @@ pub(crate) fn write_bitmap_to_bytes( match container { Container::Bits(bits) => { for chunk in bits.iter() { - out.write_u64::(*chunk)?; + out.write_all(&u64::to_le_bytes(*chunk))?; } } Container::Array(array) => { for value in array.iter() { - out.write_u16::(*value)?; + out.write_all(&u16::to_le_bytes(*value))?; } } Container::Run(runs) => { - out.write_u16::((runs.len()).try_into().unwrap())?; + out.write_all(&u16::to_le_bytes(runs.len().try_into().unwrap()))?; for (start, lenm1) in runs.iter().copied() { - out.write_u16::(start)?; - out.write_u16::(lenm1)?; + out.write_all(&u16::to_le_bytes(start))?; + out.write_all(&u16::to_le_bytes(lenm1))?; } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 74c9130fd77bd..80a4ea0424a26 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1133,6 +1133,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ .setting-check input:checked { background-color: var(--settings-input-color); border-width: 1px; + /* cross-mark image in the settings checkboxes */ content: url('data:image/svg+xml,\ \ '); @@ -1608,12 +1609,26 @@ a.tooltip:hover::after { font-size: 0; } #settings-menu > a:before { - content: url('wheel-63255fc4502dca9a.svg'); + /* Wheel */ + content: url('data:image/svg+xml,\ + '); width: 22px; height: 22px; } #sidebar-button > a:before { + /* sidebar resizer image */ content: url('data:image/svg+xml,\ \ @@ -1636,7 +1651,17 @@ a.tooltip:hover::after { } #copy-path::before { filter: var(--copy-path-img-filter); - content: url('clipboard-24048e6d87f63d07.svg'); + /* clipboard */ + content: url('data:image/svg+xml,\ +\ +\ +'); + width: 19px; + height: 18px; } #copy-path:hover::before { filter: var(--copy-path-img-hover-filter); @@ -1837,6 +1862,7 @@ However, it's not needed with smaller screen width because the doc/code block is /* sidebar button opens modal use hamburger button */ .src #sidebar-button > a:before, .sidebar-menu-toggle:before { + /* hamburger button image */ content: url('data:image/svg+xml,\ '); @@ -1850,6 +1876,7 @@ However, it's not needed with smaller screen width because the doc/code block is /* src sidebar button opens a folder view */ .src #sidebar-button > a:before { + /* folder image */ content: url('data:image/svg+xml,\ \ diff --git a/src/librustdoc/html/static/images/clipboard.svg b/src/librustdoc/html/static/images/clipboard.svg deleted file mode 100644 index e437c83fb6b6d..0000000000000 --- a/src/librustdoc/html/static/images/clipboard.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/librustdoc/html/static/images/wheel.svg b/src/librustdoc/html/static/images/wheel.svg deleted file mode 100644 index ba30f13dd58e9..0000000000000 --- a/src/librustdoc/html/static/images/wheel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index d8874c2fda0a0..035376bace9c7 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -99,8 +99,6 @@ static_files! { src_script_js => "static/js/src-script.js", storage_js => "static/js/storage.js", scrape_examples_js => "static/js/scrape-examples.js", - wheel_svg => "static/images/wheel.svg", - clipboard_svg => "static/images/clipboard.svg", copyright => "static/COPYRIGHT.txt", license_apache => "static/LICENSE-APACHE.txt", license_mit => "static/LICENSE-MIT.txt", diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index f78743a7917ce..dd2bb47e5926b 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -187,7 +187,7 @@ declare_rustdoc_lint! { declare_rustdoc_lint! { /// This lint is **warn-by-default**. It detects explicit links that are the same - /// as computed automatic links. This usually means the explicit links are removeable. + /// as computed automatic links. This usually means the explicit links are removable. /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#redundant_explicit_links diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1ba4e6cbdf058..747f5c0a83562 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1420,7 +1420,7 @@ impl LinkCollector<'_, '_> { // // Otherwise, check if 2 links are same, if so, skip the resolve process. // - // Notice that this algorithm is passive, might possibly miss actual redudant cases. + // Notice that this algorithm is passive, might possibly miss actual redundant cases. let explicit_link = explicit_link.to_string(); let display_text = ori_link.display_text.as_ref().unwrap(); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 89d6f8d67f101..e788069ea804c 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -314,7 +314,7 @@ pub enum StructKind { /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and /// `#[doc(hidden)]` fields will be given as `None` Tuple(Vec>), - /// A struct with nammed fields. + /// A struct with named fields. /// /// ```rust /// pub struct PlainStruct { x: i32 } diff --git a/src/stage0.json b/src/stage0.json index a85fbf254fcfa..a9a53a7528fee 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -18,431 +18,439 @@ "tool is executed." ], "compiler": { - "date": "2024-03-19", + "date": "2024-04-29", "version": "beta" }, "rustfmt": { - "date": "2024-03-19", + "date": "2024-04-29", "version": "nightly" }, "checksums_sha256": { - "dist/2024-03-19/cargo-beta-aarch64-apple-darwin.tar.gz": "d8aeeb8d427c346112020b84de85c1498d1ea043a01a45dd63d38da8ae0d35d1", - "dist/2024-03-19/cargo-beta-aarch64-apple-darwin.tar.xz": "f4c3aec8e916a93412c6c798c43dab1dd64c0095509a2a255191751a230730ad", - "dist/2024-03-19/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "d6161a55f808b6d54a061f9ffd9c33489b844f450f07a40e2f6cdb7def75792b", - "dist/2024-03-19/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "cba6e510866f9d920ee40e66069e8d152c0bfdabcc280ba0175a103460614839", - "dist/2024-03-19/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "e99299705d9b596554a4156ca7e8cd1bab95d926b519fd79e24d7b4c00bf4bbe", - "dist/2024-03-19/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "d006ecc2215a0b7b1d3040c64d72094589bfe11f1ffd34f63e5aaa8fb52ee4b2", - "dist/2024-03-19/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "9f6b9bd599948b48085bf592630963a5b69608abff67dd3674327d7efdcbf695", - "dist/2024-03-19/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "e3bd8ad798b098f1e03333bece43fe163f4d4b613bf38de4809106ca98b99c05", - "dist/2024-03-19/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "5ec13385ad03d14fa8fd48fd3f92df123a1626bb8a594df33c0bdee02d5a811c", - "dist/2024-03-19/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "bf201ad295272ee9435da1afcd4888c31bb14e467edb9638fdfe95b071bc869d", - "dist/2024-03-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "0e09177180c2822378bdb66dca69fb8bc7e7d5c51f414bdd95b9497c683d466f", - "dist/2024-03-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "5815c1421d474d8cd238fff80db5ba5231155abbd8642eeced84842d34f49ba9", - "dist/2024-03-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "36967ecac443fdcace710bae63eedcf65a4c2015793ed30ea3edae3d93f24707", - "dist/2024-03-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "1932898203f99c2aee95e71226c66b48d8dcbe40aa3a8b0782856fedcd291b13", - "dist/2024-03-19/cargo-beta-i686-pc-windows-gnu.tar.gz": "948157661b4b54b4c963933d97d4721efb6c8134242b96a82b86ee4be8dfe043", - "dist/2024-03-19/cargo-beta-i686-pc-windows-gnu.tar.xz": "26afbb06b1a47945172cee64470803670d1e41529f4e0f357f48633565efc489", - "dist/2024-03-19/cargo-beta-i686-pc-windows-msvc.tar.gz": "82e81f26ba6a207ac891a13bd9eb58c2cc33d31e78d354a210c4518b2d2b4dfd", - "dist/2024-03-19/cargo-beta-i686-pc-windows-msvc.tar.xz": "2b697674c4535bb58910dea6fdb9948a3b06ecdb723a638c01558615cbbf3fb0", - "dist/2024-03-19/cargo-beta-i686-unknown-linux-gnu.tar.gz": "2273118fc50fe605d53b078b5859d2694555f6c9ce2a61478f5af1765cffb997", - "dist/2024-03-19/cargo-beta-i686-unknown-linux-gnu.tar.xz": "53ae185d70ead1a251aac0793cbc784858d7a666530cacb63404541bef2a8bbd", - "dist/2024-03-19/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "f37429c8406938888600b180b60db99a5343866e8ba6c595350c60a631d6cc2e", - "dist/2024-03-19/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "ca49cac7f00c94ab5ac936c500a96092fc44a2cf9f1e10d52aa877ad9a57c548", - "dist/2024-03-19/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "262a48b6cfe9ebc8e19847e5ffa22459398395a9f9c9bb0891bf7b247b9d800a", - "dist/2024-03-19/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "6300c528f7457e0349eb2ff25e24122e5448855a4f05f265b810b328d4310516", - "dist/2024-03-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "e0dd3b037664c468eee9340235454b0a01310eae6025d5e2fb142027ff079cd5", - "dist/2024-03-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "36de5c67fdbc1eacdf00a51e2b44df5c1ee50ecd83755e893b6cb41bf49f30b5", - "dist/2024-03-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "cb5cdabb2d9d0398895b491f3cd128bd16488464fb3b8bc24f8e2e115154bbbf", - "dist/2024-03-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e597718951b6f2973a68d587b84b6d4ce51e180e74b1060fdcbc3cfd05e04291", - "dist/2024-03-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "0a860fccb3f7ca44ca94ed76b1b81a2033e9c6806b32b428b49794508529e5be", - "dist/2024-03-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "10eaa329dc9a40337df22edd21a7396fd87852afcd0e68f1334cb374a56aa5bf", - "dist/2024-03-19/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "2f511c9d6ba6b489d96f531778af89baa3cce98ddc2e015198a0fbda95c0077a", - "dist/2024-03-19/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "d510515fa11961e56c05a946fb7200ce42b3831280177fda78260915f9b0192f", - "dist/2024-03-19/cargo-beta-x86_64-apple-darwin.tar.gz": "e4d542ce10c993bbdd1103d605c5c15771629750f204c5de76af93b0f0278391", - "dist/2024-03-19/cargo-beta-x86_64-apple-darwin.tar.xz": "36ff8a7806bd8bcb2c0054f994ec32bc5b30907c3ea2dd3cd07a440b6ee031c3", - "dist/2024-03-19/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "d3daaa2be8f7b761c37cfca9a1a242e2b0231795e1cb868246ed1e379c3969d8", - "dist/2024-03-19/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "1cda9d7c448336878071e6eb27338bd0346ec5ea28a8d29a6dcb3caa9b96fc54", - "dist/2024-03-19/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "cd1539eca02777df1ff8bf70d4f4abe59ea3a2d1cc625fb714b941502f863198", - "dist/2024-03-19/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "e97a05c1ba1a4aec2d424845b0b874712f15568c2e9cd61222663b96b759bb3f", - "dist/2024-03-19/cargo-beta-x86_64-unknown-freebsd.tar.gz": "aa2de3a607bc0fd4b4f99b2a6c8c024a75823d7ebea553748d24ad2841f3c919", - "dist/2024-03-19/cargo-beta-x86_64-unknown-freebsd.tar.xz": "6546733a7b4a34b5739b9a1d1cfac8eb7ae320a14a242e8298564e33b2b4208e", - "dist/2024-03-19/cargo-beta-x86_64-unknown-illumos.tar.gz": "e48ad6cfa052ee84226e79cd037b4ff02d6974139225a69edac26db10f894c12", - "dist/2024-03-19/cargo-beta-x86_64-unknown-illumos.tar.xz": "2a55ac5d8aecb87d7625a90a5f1560859f516a44825b189b7d0cbbe0de787bd6", - "dist/2024-03-19/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "19db36d6b51c3e16869fc4be4133e321b103211fa8fd7a072dfb8dfa5dd108b6", - "dist/2024-03-19/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "97a90f062125ed14fc9723ecf3e68e12fc5853efb83e0afeef97dadd1b0e032f", - "dist/2024-03-19/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "231529bb7dbefbdba9b741a03ed210963966e217b684b05bfe8ff61af46577c9", - "dist/2024-03-19/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "b5e82d094176f729dc500d67ef5f4102df558718020f43536155ac4a74d6a01b", - "dist/2024-03-19/cargo-beta-x86_64-unknown-netbsd.tar.gz": "c6b836aa6f7cd086a7316fbcaf9e3de080d310db60eacc0910a3b90bbf5c224e", - "dist/2024-03-19/cargo-beta-x86_64-unknown-netbsd.tar.xz": "dcb398fb25568a0e5374be22be14f8dc1c0a7221fc5e60dc9258d4767f774058", - "dist/2024-03-19/clippy-beta-aarch64-apple-darwin.tar.gz": "7f4cf1177f0f22f471b8bf219d13b59b626089b3c2a563b3559dc66a573c8375", - "dist/2024-03-19/clippy-beta-aarch64-apple-darwin.tar.xz": "78d5efca461180bfdcde7e4672ac06221a0809386624b4f6892e0037df8be572", - "dist/2024-03-19/clippy-beta-aarch64-pc-windows-msvc.tar.gz": "8d3443465b4f0cbd6ba7e5bd8614071ce826798f80d7c6e35cc71ef463675952", - "dist/2024-03-19/clippy-beta-aarch64-pc-windows-msvc.tar.xz": "4ea23f92b8f36a271c36df93008a00e0a0519dfdc0da69cc920f7edf317b4ae9", - "dist/2024-03-19/clippy-beta-aarch64-unknown-linux-gnu.tar.gz": "1eabd5f5bce761972022f52dc86cd408f7106a7df2a0d9b1701afc1bcb39ed39", - "dist/2024-03-19/clippy-beta-aarch64-unknown-linux-gnu.tar.xz": "05feb29e8c526ed85e331f091b046767c4a01d68129c6a873536703dee529323", - "dist/2024-03-19/clippy-beta-aarch64-unknown-linux-musl.tar.gz": "c023d628e7d23ad3d94791e595b0ce4033c24b5e53f806947b88a6cddd93e1b8", - "dist/2024-03-19/clippy-beta-aarch64-unknown-linux-musl.tar.xz": "96b29dba180d5bf4caa40b5c8538248b0b820991d91eab819b2ce0fe093640b9", - "dist/2024-03-19/clippy-beta-arm-unknown-linux-gnueabi.tar.gz": "5d9a8237c5d2258e7ff18cee7cad2308e6ce3935251c8fb74932ed84b1e23a52", - "dist/2024-03-19/clippy-beta-arm-unknown-linux-gnueabi.tar.xz": "625f0415d85c08281efb4cdd6d362636876360774297487ed92337e72058c896", - "dist/2024-03-19/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz": "5d9e03efe64eb1a60dfa011b1641a74979295cf6540e081672deed82fd130132", - "dist/2024-03-19/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz": "e9bed26481e7678e7e4388c0e6885ab323b9cecc270a3044b08cb681eed5333d", - "dist/2024-03-19/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz": "26e0a630657c7abe765132bfab93aa39013ff19aec1978e41968cb53e6c46693", - "dist/2024-03-19/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz": "30abee9b263f4ff6f7e696a41f5356957daae5953c224fcd1f253ce41dcd94ea", - "dist/2024-03-19/clippy-beta-i686-pc-windows-gnu.tar.gz": "845732a863b79922ed5057ddf7c911bae71381082bdcf68799c8f79c0f48d192", - "dist/2024-03-19/clippy-beta-i686-pc-windows-gnu.tar.xz": "75f1abca075af64656d176ac1ea37e24c000378f1750a708924b44fdc223c389", - "dist/2024-03-19/clippy-beta-i686-pc-windows-msvc.tar.gz": "e5a7d0ff6d1f8d9bfeaab8f8aaf1c18528c1eb447169454c965838a2b836c201", - "dist/2024-03-19/clippy-beta-i686-pc-windows-msvc.tar.xz": "ad5a7313ca6fbd8051c0db761bbae67d3405cc5a98ec20891f26c15b31b5b2b0", - "dist/2024-03-19/clippy-beta-i686-unknown-linux-gnu.tar.gz": "cf67172fcc26b9b45138f0ac12721c1fe226a892346145b4a0ff1931d60fb756", - "dist/2024-03-19/clippy-beta-i686-unknown-linux-gnu.tar.xz": "3adb4d8a782a80d85f4cdfc433f63656449a06dddc67f0b11bf399d9a8aae97a", - "dist/2024-03-19/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz": "175d58f41d0b08bc1ac733bee1d16db31a4a64f7703a87ea1f13ec72b19be4d7", - "dist/2024-03-19/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz": "73925325e092d84ba3a8aff695953142962221fecaab9d57dc61b4d03338bb12", - "dist/2024-03-19/clippy-beta-powerpc-unknown-linux-gnu.tar.gz": "cec90ecbdfd252e49de68fa69806f5662bd4f4ab093708104e19b228564c0ee4", - "dist/2024-03-19/clippy-beta-powerpc-unknown-linux-gnu.tar.xz": "eb085114c178c8e16ec77657fb658b537eff1125f3de5d7e07f1ccd62e8b834e", - "dist/2024-03-19/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz": "b599d42a4100a7b1304eee34571abe1e6e38e873f8197e46d0d4d92dbb0ccd27", - "dist/2024-03-19/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz": "57338b860b283cfed3cf1eb38083113f026cfc91135e439b75de1a3acc9e42b3", - "dist/2024-03-19/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz": "00f756d858949ad83ad32dca5c5a93cd283da3c91f4976564afd5be3b4f5927b", - "dist/2024-03-19/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4a8d250c30312dfd4f8d259ca4376555bbc6cf290a884aff92e6b06a852acf6d", - "dist/2024-03-19/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz": "992a77181709bf235c1e0a335a82b0ee01fe8f749956f2aad52a386685aeae6b", - "dist/2024-03-19/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz": "b523cf81d4ffbcc0bb9f4f5805eeb39624901eea591c852f9594690350848c54", - "dist/2024-03-19/clippy-beta-s390x-unknown-linux-gnu.tar.gz": "5f22463a8c138fb3934a405bc0f7de4b5ea51c86b75f7739eccd7181fbeb4e9a", - "dist/2024-03-19/clippy-beta-s390x-unknown-linux-gnu.tar.xz": "2b507322b80e562a0dfaba16210a2f1d65051a740869ce5a952bf83a9099e0f2", - "dist/2024-03-19/clippy-beta-x86_64-apple-darwin.tar.gz": "6873e1a437b6783e349d4fe1cd69f996f579b623c231d55933ec194de19d0a15", - "dist/2024-03-19/clippy-beta-x86_64-apple-darwin.tar.xz": "4b8f43b267b25bc5f60541fe6b98254c2731f0ee55129cc132e28c4f3b2bbc24", - "dist/2024-03-19/clippy-beta-x86_64-pc-windows-gnu.tar.gz": "e697e4c34422519db58b44bf8ed164fc45dadf4ac114c3e662f6990d4d9a5522", - "dist/2024-03-19/clippy-beta-x86_64-pc-windows-gnu.tar.xz": "5ffd1038684dc68bf97f9a74c08beca4c3eb66b39b11e32e7da45b763fe1f7f2", - "dist/2024-03-19/clippy-beta-x86_64-pc-windows-msvc.tar.gz": "7e334464dbbe5be014de9ef6872a1b2066016204e7ae8c11e55fbf64bedb93da", - "dist/2024-03-19/clippy-beta-x86_64-pc-windows-msvc.tar.xz": "55b4aaa0a64d9e3cc2489a678935277d91b1f8223186c52b59bd33dbd403d52a", - "dist/2024-03-19/clippy-beta-x86_64-unknown-freebsd.tar.gz": "6fa2e2bdd09242ab44ad35853cf9493ad57d602536406ecd3504db5af87b827a", - "dist/2024-03-19/clippy-beta-x86_64-unknown-freebsd.tar.xz": "b1b79f8130d61c92d3d101a4d24416ef37fd446f18de0745be2c1fed7b276b57", - "dist/2024-03-19/clippy-beta-x86_64-unknown-illumos.tar.gz": "ee1af20cc23288fecf8ebe33e877e1de3184711a38ea378a6f4da158919b4059", - "dist/2024-03-19/clippy-beta-x86_64-unknown-illumos.tar.xz": "af724f142b19b7436547a5eb2b2b40d1acf959a73feca03efd9178948af9326a", - "dist/2024-03-19/clippy-beta-x86_64-unknown-linux-gnu.tar.gz": "376cf1787e41ba9d231191f6cae260895be18c3ececc2f2e934e850de7f1cbda", - "dist/2024-03-19/clippy-beta-x86_64-unknown-linux-gnu.tar.xz": "8d7af83d3594a151564f351eed4cdfd1c7eb5b07e073e12c6d7b7ef9ad597007", - "dist/2024-03-19/clippy-beta-x86_64-unknown-linux-musl.tar.gz": "218168e4817f70f65651f3b9561ba8e8dd3e0d8c8a33a88ba9ad0a4a501468bd", - "dist/2024-03-19/clippy-beta-x86_64-unknown-linux-musl.tar.xz": "f55143ece3326ac8c004b77e59c1a60a70b3f1189c7e2e442183097f1cf639c2", - "dist/2024-03-19/clippy-beta-x86_64-unknown-netbsd.tar.gz": "9a5c08d2e00d2f38de5a9882fe7dcadd6307a333b8caf5826687301f8d97d09a", - "dist/2024-03-19/clippy-beta-x86_64-unknown-netbsd.tar.xz": "7be02599b4c2cd26365075ebfbb1534f6875d85501fe5a300895506e41ad0824", - "dist/2024-03-19/rust-std-beta-aarch64-apple-darwin.tar.gz": "7238015aa0e8553b6e820483e15f08119fa0b6c074abe127be99fa990f132c8f", - "dist/2024-03-19/rust-std-beta-aarch64-apple-darwin.tar.xz": "0dc783f3865ddf6512721abcd9c668f6d8533c3581015cfd4740b40cb09ce199", - "dist/2024-03-19/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "90541bf8f4c1fb838fff2620b55addee59687b16d3f10f92b59a41936ffa143d", - "dist/2024-03-19/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b0d14d73d404197994e41deb2d92049ec043c875a81dda52c4e4fc64e53c8065", - "dist/2024-03-19/rust-std-beta-aarch64-apple-ios.tar.gz": "3105f19fd78bcdc5171cf4041aca9da236150e43ef9c32ee1163aafbc79d311f", - "dist/2024-03-19/rust-std-beta-aarch64-apple-ios.tar.xz": "13629cec9404312c6b42fd7aac14edc5eee98947be5152ae5708db899d2ebb4e", - "dist/2024-03-19/rust-std-beta-aarch64-linux-android.tar.gz": "3fb671809fafdabcb4cd8ea6c00caf3cfa2da3421770c08abf761456f079c425", - "dist/2024-03-19/rust-std-beta-aarch64-linux-android.tar.xz": "8f8f22bd89a29db1a549414440da19f3100abb689fb095c3e09ef28a223ee3cd", - "dist/2024-03-19/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "2326cc5061a6acc3cfea5a0e2ea965e07a0103052cfb4435e5dc947573b62e11", - "dist/2024-03-19/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "87327aa9f683ef9f574348cc0ec58b0f88fdcd6563d51b69664b3588897783ca", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "5f589736703a21a17366dd93c36ee6f597a40999ce6c305ff1e007918fe6aaef", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "65386ce4aa697b74c463e1c8d793ded996f6dbf1327242aaf61471968212c1e7", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "590b12f5fdf32251c1e0ad2af619b70b73a888d3a33a705f023b81369bcbbfa8", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "c22e0e88e1fd0041c95317bbc0e39e7d4e4e6a8d73eedc141628ec9e41d844f5", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "7e8e04e2bd58ac03c5dcf017562d3ad92993896a5f5a31e199990685adb206b7", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "8d0c5b70230122904e36731290f62dcf24fca2390d4c892aeb9b8f241d380563", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz": "89d476e9654dce23fb77cef86831813d143435e4e1a9547936f5eabb9a7e649b", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz": "b1b5c25e682961301e60f115eba6177a1be97b3157a0671c0ec64563765ddfdd", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "e8b2b4cd75800e5cd5b8f5ad97d6ef9fef8e6a7852a227406e89a3f7f50d33d2", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "e5c603df1515777eb1af5c9532194fde8ea3554abfefb93499025a9a98fdc182", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-none.tar.gz": "55605666a2bde23365937c811899f9e61855a28668d4b050834b83f5af8b03b5", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-none.tar.xz": "f68fa43e4ee4d86b7bba6c316efba5ef6e3d500b0659ba4a0295df814beca459", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-uefi.tar.gz": "5b9dbe42c686670836ba26acab3afa218fa70b616d3a7951298ce5cf2eff88bd", - "dist/2024-03-19/rust-std-beta-aarch64-unknown-uefi.tar.xz": "fcc8316db3cef3a3c3240a490d18162cf724fceecb595a0c40067c6a20a53caf", - "dist/2024-03-19/rust-std-beta-arm-linux-androideabi.tar.gz": "abdd4c98992cf2f9a9a558c5c74283826de3bb48d7743e67ef1f9d1dbc40f534", - "dist/2024-03-19/rust-std-beta-arm-linux-androideabi.tar.xz": "c597c457071b82c8842958c6ad383db30741952b06b40f138a5bed3bbca62c70", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "2a11714a2e5d18f7f255feece850a4c8ab7e1b14f6eb116c47eb972825abfdc2", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "5a6f054ebf50bf4bb196a32019276bed1cbcb74cbd3d46877a48ed77c09638c9", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "422d4d3a2f32a1739d18c208e89e5c490ce9b85c771726b21d265cb7632ffd49", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "d9fb3be5b4d577a469f4dc9cce5e4631741d6661a994d15cc1db847ab4edcaed", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "6a9c25b659a7d16f01148144883e47bddb29e2d79f7b590f58efd4b002abe38e", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "2c797105730a6a2a9d8ec5506f2028d42aef48d7ae09fad11e1ef3a0dc3c9a81", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "4f58e423159b7b5a8d546c288572dc644e73cfd5e22eb87f98670e1bdd4cfb42", - "dist/2024-03-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "d549997c4be8efe2feee163096b370ca6ddb0884dbf82af0c1d08e5f652a3b26", - "dist/2024-03-19/rust-std-beta-armebv7r-none-eabi.tar.gz": "2e199f5246edf22faf1b8876bec5290a7a111a38cffb831fedef3f4d4e57dded", - "dist/2024-03-19/rust-std-beta-armebv7r-none-eabi.tar.xz": "ffc4118d0520df6d4101c05c4df31bdbe91ce302b37d9d41e3dfdfd8fcb5b49a", - "dist/2024-03-19/rust-std-beta-armebv7r-none-eabihf.tar.gz": "39e2a7464ef3e48104873f59b6198cad8333835a0fe46805b00f2a3a8f1989aa", - "dist/2024-03-19/rust-std-beta-armebv7r-none-eabihf.tar.xz": "ff22a6f9b7c7873fe84943bbcffabba04e2632166ce63e405056ca0ee8fcdb62", - "dist/2024-03-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "51128c12bcd8935bed76a555da1e403e1b374155278ed957d078a2c887512a15", - "dist/2024-03-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "5370c2da10bc8efe00f0840d8ea6f664d38518288ed402a4ac164ae71cf1dfe9", - "dist/2024-03-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "ba104dbdcc3c8689dadb75c6a85d83419e32fe78f43039f5294020da2ab3b73a", - "dist/2024-03-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "7bb849dae31f472febd722dc7dd324f073b2739dc57c40a6590b10f61c26133e", - "dist/2024-03-19/rust-std-beta-armv7-linux-androideabi.tar.gz": "c44211a45a1ecb9b5800fb7a3b7fa88de4562845888588012b34e282e26cb4f8", - "dist/2024-03-19/rust-std-beta-armv7-linux-androideabi.tar.xz": "3a92cdd368559d06d290af58fda93eac98e6d4bfd4e6ad03db0f91fe01789504", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "f00db0fd04a921cebe68a21d3c923e44f8a1828cdfffa201826d333feb0b9bd6", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "af5ec7e114c8558080b8891269cca098b530809085577485ea96435d5f664e4b", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5b2aa8f0c2a005a5c98dd08a6d4d231a11992356f857b706a19cefa66d62dc9a", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7ab1a7cda6ae70836df20a70283af166ad2d5413755485d818d8760f3bf69f6c", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "9b970f2b3e0a01ecf56a9d32cdfbc47d76a2518838bc231d4488c2f4a9426fa7", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "934272fbb78cd09728ef03557fad7e2b1b9302f88579dee8a5a1f58c8f4b15bd", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "f70a1adf38b2d22b1706af807023154b626f656efb8d91c8ed7235bfe0855edf", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "a665e05bb8dff2e8dd0479cb8a63460c73ee3e86ec7e1b6f48fece2985c85e52", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-ohos.tar.gz": "e0ec71714bceee0df1bcdb85e094b58359d41f273dc9abab7ac05346fcd3f4b9", - "dist/2024-03-19/rust-std-beta-armv7-unknown-linux-ohos.tar.xz": "afbcd9b7ecc92f69801d77185af0139136ba6c352d14a6c8ed76de64a87645f5", - "dist/2024-03-19/rust-std-beta-armv7a-none-eabi.tar.gz": "a0e55f17c1bab81bf836c1e373f77d25c42fbd05f04b8b0e96f66f1f744481d2", - "dist/2024-03-19/rust-std-beta-armv7a-none-eabi.tar.xz": "f2dd0221e76d7b9f51e9efdee2e40c8d7539b1d5f52257f89431f29931394510", - "dist/2024-03-19/rust-std-beta-armv7r-none-eabi.tar.gz": "e97324f421bb354bc841a20e8b1c0357e633595bec4fca510f06e56fb89b2a6a", - "dist/2024-03-19/rust-std-beta-armv7r-none-eabi.tar.xz": "1ce1ca60b9536ede90452621ba91539b8ca6b6bdf7cbda3bd6d0b04a28c09580", - "dist/2024-03-19/rust-std-beta-armv7r-none-eabihf.tar.gz": "9bffa04e8cd3f67d8892f851b269f9cd91f6c9e5f2c87c641e9f6ef24bf7b644", - "dist/2024-03-19/rust-std-beta-armv7r-none-eabihf.tar.xz": "2a3cd2ab92cc37698057629167a553d0654f7882bfc1eb46687e1014b4b8e379", - "dist/2024-03-19/rust-std-beta-i586-pc-windows-msvc.tar.gz": "284f13947d990587090beb32262e4a83089c56ce2c3a1ffb89ed0fc5f4661eb3", - "dist/2024-03-19/rust-std-beta-i586-pc-windows-msvc.tar.xz": "22e641bdd54b3a7030c2eda0ff20a5517607fb6e60ea6d3195a2cd3afb0e984a", - "dist/2024-03-19/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "adaaf6d3a291640ddaa3d522d8331cb27ea899999681d57713b57c879b55de96", - "dist/2024-03-19/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ebe80c2420c0eedd219cd539b87de75ffc0ed3b1656284cb81e2b2e8a927c738", - "dist/2024-03-19/rust-std-beta-i586-unknown-linux-musl.tar.gz": "c2e4691bf6956f97a214ef80f015a77ec4ece4ee32e9bc73300fe1c0267dcabe", - "dist/2024-03-19/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e67059e579532ceb06a46702cc561acbeb3ba6258eda47418da587ec45759e26", - "dist/2024-03-19/rust-std-beta-i686-linux-android.tar.gz": "f112053adbcce7710383afe1681bd0096444a516f78f576e29f2f3c76468e7f0", - "dist/2024-03-19/rust-std-beta-i686-linux-android.tar.xz": "e63ae04fc20519fb5a56c2bae49f767807cb1ae1c01cab34dee1d129b34c4dee", - "dist/2024-03-19/rust-std-beta-i686-pc-windows-gnu.tar.gz": "14b36d2952ebaa84bf24645cd5d3464ae2b9df4d3ffee4bd48fedb07a4fdb09d", - "dist/2024-03-19/rust-std-beta-i686-pc-windows-gnu.tar.xz": "fef8c1bd4e1ceab680e1856b35f4ed426d07c224fa60c92d12efe0dfe700abc9", - "dist/2024-03-19/rust-std-beta-i686-pc-windows-msvc.tar.gz": "b42794fb8feda98c99d36dd978373afbfab56fd374fe42318107c453ab4d0fb7", - "dist/2024-03-19/rust-std-beta-i686-pc-windows-msvc.tar.xz": "855ed5996d9d8e4bc2424ce5ea6da6155b23357d700f1fc07d69d0bd12672a8f", - "dist/2024-03-19/rust-std-beta-i686-unknown-freebsd.tar.gz": "0ac04b35b62c7d8fe42ee29854b6a40b7dcf0d3deb174031a7620d2c87a8b206", - "dist/2024-03-19/rust-std-beta-i686-unknown-freebsd.tar.xz": "0287daaa3042c644d3190c6262b60b580a0cdfd80c64c299a36e0636d38e5674", - "dist/2024-03-19/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "647dd5ba2f4d842d6bd6377e99b67b3d65d3ee47ea800ace9d172e9d24f63eb0", - "dist/2024-03-19/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "d705b0cce3492e863c5d8fb28b4f2bedce68637fd7093d24a9e86ff6d2d0ca56", - "dist/2024-03-19/rust-std-beta-i686-unknown-linux-musl.tar.gz": "561ca95399cbd2f6692e5194ab550e9e0f0f5016aa2802522131c1361d3ef467", - "dist/2024-03-19/rust-std-beta-i686-unknown-linux-musl.tar.xz": "d4751c26585e512211157e162f0d1504a1854249dd6eff7262a55b09834d29fd", - "dist/2024-03-19/rust-std-beta-i686-unknown-uefi.tar.gz": "4e0a84f3dbc742d589d35cd58980157072f17090472c31ed0e306dad049a75ec", - "dist/2024-03-19/rust-std-beta-i686-unknown-uefi.tar.xz": "e11820072ae90861c96b0c1c931d691a157cccbf5d44685e3d5ff9b075aa7500", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "4357b6646ed0f379d9d74358457db1a18289967a880567b9bbff480e72f13711", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "3ffb178cb4c24b3b6df4aacbfaa4280eb6e781cd471fe52ed0b9be8fa555617b", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz": "bc32e2189cfb3efd8365bcd31fad504cab0fdf62c9fe04a6a0389ff23486cc2b", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz": "0d2894fe5fa5360cb31e5267e980faddd8d9f7adc415747991381aae535210eb", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-none.tar.gz": "16c134291f43694fb92d3efd92abc9c957d3ffa8ba8dee0c792d77f3b4d2cdd7", - "dist/2024-03-19/rust-std-beta-loongarch64-unknown-none.tar.xz": "ca06f72e2bd7309831464152cc7532a27406c18e2d6cd02918109aa65896be1e", - "dist/2024-03-19/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "a2d4f9671514673abc87ade8237508bd41df1bb6b75b0ea92bb27dd7ab75303e", - "dist/2024-03-19/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "69a8f2751d0a86878b92bb052ca0d3394f5bc0545fd3f2c1ce7e03e1ecc6d0b5", - "dist/2024-03-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "95c4f0f944b4b8ad08c4d0350a09be233796991b8790fc0d48dbae895953d73d", - "dist/2024-03-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "8ae7b77e0c7be184f4f279365eb2d9b7e9182ec9ea10f987814d4f4b50937f95", - "dist/2024-03-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "4f886546746f227bff157959a9982529895d52737b6137bf44545e82fe522672", - "dist/2024-03-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "b9fd4eda7aa2d5eb70e47405ba5fac8d5d3d15d1de76bb5d2f9d0ba8da4a2115", - "dist/2024-03-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "8e81b39b1d7cbc180fe9540e9420f68216aa9b3bd46d6cc6f758f473d8d54ae7", - "dist/2024-03-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "29d4e64b6e2a326bb695e42354e4f8a21382c63cd8a93fae64a44f3398de0a96", - "dist/2024-03-19/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "66eb8d049d50532512d442efef67993fa3da0fc0a585e549559d2e843c7e3c89", - "dist/2024-03-19/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "1919690c47b603ff6ddcf6d8f16573cc3acd960d27dfb97358dd9c92a907c766", - "dist/2024-03-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "e66c025f225b3cfc3399992b0dc3e5f6829ef03b6527656376a0575c970dd43a", - "dist/2024-03-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "75373475011adc1d3340dcf222e594be505116fa4c1099b493a6eb1018dc5f92", - "dist/2024-03-19/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz": "2dc076319958052445c0de0d34567162745d9a6de18edff2edbf6afa05feb124", - "dist/2024-03-19/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz": "f1225e56a378ac5b8790e9299815987c618f5d712a11e2a039580965679119a1", - "dist/2024-03-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "26bb1e505811310fecd47e7aa5b75cbbaf6794ce209df200ac554ff84a353392", - "dist/2024-03-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "35b4799e26da0d6220c0372bce45e6b3b18a4035b82a36505c052e0990cba754", - "dist/2024-03-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "5a79d8992906ab3db7be9716de2c6434e1c8d81c1ebf725a1b413af13f9c9091", - "dist/2024-03-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "7d63304af691b1ade5f9d6e50bf82eb9958f8b3da977fbf894f3c5dab15d0ff5", - "dist/2024-03-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "1a93efe919bcb44cae9fea48aa22a1591f041041e7c59e64461ddc3298ec954b", - "dist/2024-03-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "0e17193cec07704e02fec9f4393a457f0f57082c86d4833f687a72be0a439008", - "dist/2024-03-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3ccd73bfa0926858f95f1535f1297d6adf8be62afe0a94581d267782b4e8803c", - "dist/2024-03-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "e7b4ef2f7a7d9bee1b0dd6a12aec4d52150db2fed29af2668ef5a65b727f6ce8", - "dist/2024-03-19/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "3e755b9a8fc8b66da6795ef57d9d80ed239e10adb17c23a8a64ba96f0d0b6296", - "dist/2024-03-19/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "936807926232e6fdbd2e93a646460ca9d8850367afd82bb56d21245936f73b17", - "dist/2024-03-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "168c1fb8b6f633abb699c905eaf4e970ea94c789746d7cc3a7984ffb046df446", - "dist/2024-03-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "d64b6a01542d504fe2d4ccdba0e7574e5521841a0a4fffc3d66e78086e0343a3", - "dist/2024-03-19/rust-std-beta-sparcv9-sun-solaris.tar.gz": "34992b0a74cedbaf58057f965858cf26ffdff8bece7b2b0e167c8a1d61b6651d", - "dist/2024-03-19/rust-std-beta-sparcv9-sun-solaris.tar.xz": "957c38d5485d96d62fe46c4dff5726233d7c402708c4dbb0337cd740ad759a10", - "dist/2024-03-19/rust-std-beta-thumbv6m-none-eabi.tar.gz": "7eab40ea23f0758c5ace93224e1268e2929fb7d165b7877ea2540cc2b45664ce", - "dist/2024-03-19/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d0c428c5a1aae6e78842577a5e8f3e4b393d4d3ec9c240ed3c3a0a36d4c0b19a", - "dist/2024-03-19/rust-std-beta-thumbv7em-none-eabi.tar.gz": "450b39802145dc6ebcaad6fdf99b606fda18d3f272f18d0a5e21bffa930ec877", - "dist/2024-03-19/rust-std-beta-thumbv7em-none-eabi.tar.xz": "649532a1c17da2afbcf0fb9395305bb46a76846bbc8c4fd5c153a170b525d35d", - "dist/2024-03-19/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8068584665ce0468bd420d146cfb4643e745c4ee782b352bfc16c9e7f18ed25d", - "dist/2024-03-19/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "04c1d047e2ec0347cac5ab5591ae0eda6f52c6f9281aaa4d2f4ffcd8c5af11c8", - "dist/2024-03-19/rust-std-beta-thumbv7m-none-eabi.tar.gz": "6e954aeddadbbaf088fc8d671e590eba87d4317f8716a7cca286c764131c0d73", - "dist/2024-03-19/rust-std-beta-thumbv7m-none-eabi.tar.xz": "15f8ea37798f20559f5c6c91c42acd4c883852e14228bbfe5b65865d998beba7", - "dist/2024-03-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "1c7b6e92d8727602b8e41d44b66369ddf8e65937fb1a934b2115c18816cd66eb", - "dist/2024-03-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "5679ddb9d7404a776861195ca708fc6132ce1e35fc5994946ba7a17ce61afa9c", - "dist/2024-03-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "44280bcc42edb6ff3f2d91c8a3e7005703150e7be749480577df96100d516b1c", - "dist/2024-03-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "abf86ce8dfd3bd5548cbc8c9c958eb75fbbff77cb7ae8a5e231e5ac9d46d3876", - "dist/2024-03-19/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ca4fc4970411a503d11a30bbea94487a10dc5925cdf7b1dc3bea095c72e5d381", - "dist/2024-03-19/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "9752a30a7a2dbf64092cfb1901ef4e49e9521b794644710060eaf62c8acd1d5c", - "dist/2024-03-19/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "14d29c09f788bdc63550cb9cc0ecb8040b0e28e6e5a5bc65c06dca6a0fb34821", - "dist/2024-03-19/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "201eff5b741c735547226e9a4d22aed0e09f1c31a48673ce7fc094fb7fc95ba7", - "dist/2024-03-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "1a641bcc8c904a0c5b4e7ff0d52d105a1ce45c24d10bb1cdc1dc284222851d6d", - "dist/2024-03-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "48f8abb5d1dae87c22e4d24610be6a98d646150d7bddc1ca471a6a27976090e0", - "dist/2024-03-19/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "102f692ecc5233a2e8063c305a0d37ffb9689fc1a4927dcd8f4fa14501a04a0b", - "dist/2024-03-19/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "cd0407c881219b7586500c05b711ed78de9356d7c0db1065baab3833b5d2b738", - "dist/2024-03-19/rust-std-beta-wasm32-unknown-unknown.tar.gz": "3e588580f9298626c4bc3e4b0ad52495d97e4dfc61ca8778e97da3e67c624266", - "dist/2024-03-19/rust-std-beta-wasm32-unknown-unknown.tar.xz": "665dd07fe6ab4d2bcbdc7e88b674e90ff4ea8caff9251d572ff0a7edb32a509d", - "dist/2024-03-19/rust-std-beta-wasm32-wasi.tar.gz": "c0249f7a3e1f8275323adc2a49840cfc677ce8ac3365886753135703a9276572", - "dist/2024-03-19/rust-std-beta-wasm32-wasi.tar.xz": "aad18dde6feaf251af10398b9e7ba2e39828a4640a8f30cc66ee72cd2b1278b3", - "dist/2024-03-19/rust-std-beta-wasm32-wasip1-threads.tar.gz": "95f5700c74feeecea7705d90d3022637e4fa96ee5db165d8fc76d4db05101005", - "dist/2024-03-19/rust-std-beta-wasm32-wasip1-threads.tar.xz": "6787b24af02a7216a524104379517a158938bc2c940b56a60be2ac143d3de7f8", - "dist/2024-03-19/rust-std-beta-wasm32-wasip1.tar.gz": "38d2130daea2bd3c71a456e4dfc44ad900838d15a18af123bfe971f036b43951", - "dist/2024-03-19/rust-std-beta-wasm32-wasip1.tar.xz": "a766d6af0392e913f42930a02fbe5c7b481120ebceadf6b33c7c21ba6067c7f0", - "dist/2024-03-19/rust-std-beta-x86_64-apple-darwin.tar.gz": "3de58d464ee9cfd01d245016b752d1740f9b3feca7c84dddcfeeefd288a4966e", - "dist/2024-03-19/rust-std-beta-x86_64-apple-darwin.tar.xz": "8854dbc047727f11dcdc2f243536a5a6c5e7d8986c4ecea026820630aa2cce59", - "dist/2024-03-19/rust-std-beta-x86_64-apple-ios.tar.gz": "79477ea1afc524ed9d4f3ae57df132affe03a3fa7a14b17214181543918b2391", - "dist/2024-03-19/rust-std-beta-x86_64-apple-ios.tar.xz": "b830688a420e5631406b00d40756739d71a5f8f9789a4b6f4a601db167893814", - "dist/2024-03-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "ceb9ac35511e08cbd14dcf6c4faed57107f0facd5ebe1b1634f2ce2b41781c27", - "dist/2024-03-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "532b77cbb488b445e0291997a21d0a94c44970c5793ecca07eedca2dc4b02be7", - "dist/2024-03-19/rust-std-beta-x86_64-linux-android.tar.gz": "5333bf0c8ea592ed316e21bb2938ed07d247f0f873b45f34abcaa62f2e33f741", - "dist/2024-03-19/rust-std-beta-x86_64-linux-android.tar.xz": "ab18128d48a1eac2e8577e4268d95efe9619a4789cf4ee322d5bd651f33c24c1", - "dist/2024-03-19/rust-std-beta-x86_64-pc-solaris.tar.gz": "6976af5df3468680d83f54e87f57b94ac121ee82d7887e3e21200434b993a219", - "dist/2024-03-19/rust-std-beta-x86_64-pc-solaris.tar.xz": "932ffbff886919acb32f77ab70560a0262bbf5ee83a78679598ec13fcad39e3b", - "dist/2024-03-19/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "0429be318b55a9c36bc2fdb0b9654a3cf39527cb05d75f46890f6fcc2ed003a3", - "dist/2024-03-19/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "7e3f64dc9b5b6653e6adbc58499857c0df8f1765d8fb777f6cb2ada3f40543d4", - "dist/2024-03-19/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "07a7bb2d07bb72693e0bf0ddc365394dde55063ad572259a5d171e08cda592f2", - "dist/2024-03-19/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "efc20d952b248815bda4ab3950b2998b5326e2c5008e72ede921eacb79b3b504", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "04a46c5cbfe620dc5d3d05134e0501aa466c081f848df679c554d51ecc6e8bb6", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9ed41c7d0c09409fbecf33eab630ec847a4af7ea5bcaf42d8e14e1074ed30bf4", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "de0c88a91d325087e5c28e9ca5d3092443c875b55ed08b8486e8fd1c01c7b7e8", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "e403921f889381097628bcb2c431e3b8a8c0773c0d5062d4d1a9ec8e7f88fa45", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-illumos.tar.gz": "ee045b5102673d085fbeead4d5b9daeb9497f90d341bd51c8ac85b666e9c9821", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-illumos.tar.xz": "bd24fda28c9b69cc68c90b910a75cd652ad3b4d4430f802d8a2354c2cd5d19e7", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "8c70c2d12202054329cf6fca88adf20d9d9f493cb057c30211454a49f96ad4e5", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "ea6673ea519a6eba60836b810c0531cac858ca74d0d756538a45a375ffb7db9f", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "52e104ce39ac5e8e44fbb332bc08f7ac3d564408f48a459f79ba2149caf47b32", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "fa098772e186acba6e85ea2f4d0270f01e00cbdd27eec1e92cbda808b7807284", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "d6785e6574b4a7ba61f66c1e7938a46a02f9430983a7aee1c3400eb5f8b57f0f", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "17c3e8254fbfed0f0a9b3209976e44a136d0f581d0713ddf7114753cfd0b983d", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz": "407f9c2d5d3bd76698af04711d9a06b7aa86d4c55cee9d8ed1ce3aa37055068e", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz": "5e0869bf268c9824c284e841b2bf5a13a6dc1bd2e55ce3b7b09788ba5608c9dc", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9b5aa240c2a696af0d342ec26a6b6ea4f5888070e8b590122379302910a978f8", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "064c1925a8ac82d1474c240c6c9414b422a7b04211a49a7660625193a0c21c64", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-none.tar.gz": "8e48a645b2b8dda6deb5b706e415697d303830775032b69521265acfc9f8608e", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-none.tar.xz": "a3d28304c75a71680d7d40aca43bf638bb4def5ec10f873aca5261692b114743", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-redox.tar.gz": "e645a81d4884f09c9d7da242ae448cadaf7a9232475707ece014a57d02a23527", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-redox.tar.xz": "0cf089464b1949a4f24092e2782b306e9530489cc415df69ae433c23a438518e", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-uefi.tar.gz": "ba7eec56d4e8a5f8a6c206b6a12fcae77da9a24ffea824c1db128dcd4a7d9fbe", - "dist/2024-03-19/rust-std-beta-x86_64-unknown-uefi.tar.xz": "76aa9bf6ed668667d1d47feb2fb8e941f5446f2ce5b4e94aacf34f964ebb3171", - "dist/2024-03-19/rustc-beta-aarch64-apple-darwin.tar.gz": "e40614daaa2b0270d5f3153c8216f68419b96dd167632dc67c1fd641ac0a21ff", - "dist/2024-03-19/rustc-beta-aarch64-apple-darwin.tar.xz": "7c2106ea1a3d358e2893a62fcc2162e041ecbdd9143f2dabbe0fa7a6b5827aaa", - "dist/2024-03-19/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "7eb0678bc1b4dfcf366641dbb02390262e47ecade1db9007ae1d5bbc39b6c7c6", - "dist/2024-03-19/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "0caef4825f0a6e51fd05c5c32365fb3a80a2b7692de71ff0af10ce9aea1ecafe", - "dist/2024-03-19/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "bbf59310c1e60725aebed09a09f0df4b1c21c2d0744f34734472e46cd7248fee", - "dist/2024-03-19/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "a7687c89bf94d64119ee76029ed12d27d594d7716fbf542852333185385a5b44", - "dist/2024-03-19/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "d2bda016eaf8b988e3b5899ab1239c582ef9119c40267b79be2efa453ceb9ee1", - "dist/2024-03-19/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "940f0611384175521401f352f4fc18a587b3816f99c88a0e130b895918c340a9", - "dist/2024-03-19/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "3ef861f5980f899b6575e50844c14ad30fe739f80538118acc8e29fd8b00cbed", - "dist/2024-03-19/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "191a2bb6966e05d1db83acafeb3caf0e0421eec539e221837e3dcff5e9db4152", - "dist/2024-03-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "9999f60a513864257a14ee58ac3b87d9e557e0c2fe720a5d4ba31d250debc378", - "dist/2024-03-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "7c824f67a45aaeb7cf4c7519aa72ce8a81013cf2edec2fb5600f68aaf6eaf84e", - "dist/2024-03-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "83fa3927f92945845c6cc5a6f123ce5301a24af81c9371e5c6bcc8964a182688", - "dist/2024-03-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "3469f087248e671351dc0bdda06c1a9b8d12fc64854148cc9404d419db8fdb02", - "dist/2024-03-19/rustc-beta-i686-pc-windows-gnu.tar.gz": "a219c9829d7e33a822947faeb3f8826d7f2f5c46aeaa9c338bc27bf7b1561395", - "dist/2024-03-19/rustc-beta-i686-pc-windows-gnu.tar.xz": "ee5f30b90bc43738eb9c9a3678a09768bcffd3bed413c50ec23fa14fea1157ac", - "dist/2024-03-19/rustc-beta-i686-pc-windows-msvc.tar.gz": "acdc6345b76ed52b5b58d2832ae61c904aa6d74955f2e31432ab363f217397ec", - "dist/2024-03-19/rustc-beta-i686-pc-windows-msvc.tar.xz": "13161baa6a6e0771fcfb65b0e26f77a1ce07c5dcdb029a624723231d5d3c1012", - "dist/2024-03-19/rustc-beta-i686-unknown-linux-gnu.tar.gz": "7188f7c598cd4f1579ca06819cac5461679513ff648f03b7f28e15fd5636467e", - "dist/2024-03-19/rustc-beta-i686-unknown-linux-gnu.tar.xz": "42e03380ac0070f1cbf47c674c1d529cb065960f5e8c0f92e24a5f994dfeca83", - "dist/2024-03-19/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "67a57b0a8a057a1d39b99e5232145d7c5a48b9e3ff0e97b9ad1f4cbda004587b", - "dist/2024-03-19/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "1c85e17bd524294ac64c2defce82eae336cc3c5d9795dab68e0d7419ede35a6a", - "dist/2024-03-19/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "1c243f95e823164a4b112fef4a70bd3cb0f368dfbff7efd106b7ec3a718f49dc", - "dist/2024-03-19/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "318d69391381a142b72a27c6e53be624691e465ffec2497676c2454bdc06f856", - "dist/2024-03-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "f8423ac9a207c9a43746b9299dab7ff55a747aba1980313f98b5aef67e489d66", - "dist/2024-03-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "f6e3552a9ad8a90dc0830f7c8beaaf10c90e4760bcb48904d4197c53a54a8b1e", - "dist/2024-03-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "3ab2d798cf0812b874198691993686e9c884d24806628242110dacfa5bc3446a", - "dist/2024-03-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "6cae9a4e5e88054800f11f028b92211173de4038ad1bb0a871cdd05bc6a0b8c1", - "dist/2024-03-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "368351e98c1e71b3fe40c687f478d52a43ba388811521e7807b314d750cb4f65", - "dist/2024-03-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "116171252c2f153066e9f8fa6eb1e63962aebdd67d14368560200c984ae38ccf", - "dist/2024-03-19/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "0445ba1954a7e6bbaf64561a33c01988a4f48aa8401669acd7c5e8ac11d27696", - "dist/2024-03-19/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "23aeed13a2c0143d14ab9fb26be47314318ee3014190ba08f5889bed14205799", - "dist/2024-03-19/rustc-beta-x86_64-apple-darwin.tar.gz": "91a1040d4b0d309fadae1b180c5cdf30c9c073245599064a075849795a8c84d6", - "dist/2024-03-19/rustc-beta-x86_64-apple-darwin.tar.xz": "996bb8bf522509e5ddf5e2d4fdfe0c19d4198605107575faba4a80e1f4de616c", - "dist/2024-03-19/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "82024a5d02148c7a0a0309105114f54dcdc6b9bb763d1e0456f0c18f96b16f57", - "dist/2024-03-19/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "b6c00535af0ef5815cfaf88bcf21b83935539785345b22abeb9d4fa97e2cc445", - "dist/2024-03-19/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "409a22e9a1ae89640059cb33d614abe84eef4096817b0fa750b3a38e0a153061", - "dist/2024-03-19/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "8fcc030bcbafdcfbd894653ce935ecb82fc04b3717718d34dd6b2a4e8d553889", - "dist/2024-03-19/rustc-beta-x86_64-unknown-freebsd.tar.gz": "79d39890188af98e9eaa1b5a15606517ad7e0b3c493bad09a59c5400bfff3d9d", - "dist/2024-03-19/rustc-beta-x86_64-unknown-freebsd.tar.xz": "b69b370559cdf73f26b83a4b5276d10988f44d39d57608c44defa6b79f92121d", - "dist/2024-03-19/rustc-beta-x86_64-unknown-illumos.tar.gz": "f4bc2b510a230a09bae4b243f1297863907c9239a94bdf739f43c31a76238a04", - "dist/2024-03-19/rustc-beta-x86_64-unknown-illumos.tar.xz": "131b02eab07b50d8a99e0185090afd6c3fd1bd20b98fc0a4830910fea5b12ec5", - "dist/2024-03-19/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "ed9d98b20a4868330c88563ec367078a4c5ed7bca497680ea690cb9da2d6ddbc", - "dist/2024-03-19/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "b6c0fec4e295b8eec2b7c8bbddec48aaba1d3c4d73803eaf887554d368b4efa5", - "dist/2024-03-19/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "e972c5ec3f9cc2661845bbb2e7153b9e90e59af2d4fcd74c588e3f326bbe9e6c", - "dist/2024-03-19/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "d576799dcd59b48ddb6d96545ec48ef517b5a7d9875033de6583387fc1d4b79a", - "dist/2024-03-19/rustc-beta-x86_64-unknown-netbsd.tar.gz": "39f5a43f70692f1bcfc6b82ef901fa86be82aa7db0f6161ea5025577976a0780", - "dist/2024-03-19/rustc-beta-x86_64-unknown-netbsd.tar.xz": "596e6681bb15420754ab1a7210157884f5e31b34a885b1d1cfcb8838ba5c28b3", - "dist/2024-03-19/rustc-nightly-aarch64-apple-darwin.tar.gz": "f91204bc62d9236adc75e2a7ba4ae41e0d9ea9c6b6bcaf0d211459cfc7d17d21", - "dist/2024-03-19/rustc-nightly-aarch64-apple-darwin.tar.xz": "7562f89f9bc9f2968ddcef0258cd5a1435855d87a1c40b9ead6b82c1cb5c58c3", - "dist/2024-03-19/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "2f1ab532837469eba7dca3cb4b45ce983384e30917b0af3108d2a8c7c88f38c5", - "dist/2024-03-19/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "fa69006e8189b1e624e0d9a9a212c15423fc1b428785f651a309eae045199f11", - "dist/2024-03-19/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "21905a47c616e3e43b05135621c17db635dfa897e2e64b124c03b042f74dff00", - "dist/2024-03-19/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "1efea63747a88b3baefe6602e047e84323867a3eeb77093b9e662ff254a85f28", - "dist/2024-03-19/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "1b693de287b60428bc1a0a23088c08680db2d0fbf4f7cf0d6e3f413cd9cfb150", - "dist/2024-03-19/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "7803e124610ad092f88b7cf4b65cd3fa1a80cb2cf5a36fe4391535ca4f3d9369", - "dist/2024-03-19/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "744bef406b6df5c610b605234375d8520abe24d8407b8bd22a0fe15de41d62b6", - "dist/2024-03-19/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "b90dc87a68c134e6fcdaa3ea20e9d0fc33b0422e4dc989c1cf0c85c8140fdfce", - "dist/2024-03-19/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "e235fd3258b7d1e42ff6609f1660a94aaafc00875c371543ad2b12ae226dd8c7", - "dist/2024-03-19/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "b37ea15820c88ae1ab534277f8f7a7ad18b3d365f1d2d499a887665b715c6c21", - "dist/2024-03-19/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "bf7cb8f0b21f2b0b8b067f88e31a2ce9e5754044b68437d4d52324fd95010161", - "dist/2024-03-19/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "3595940730b4cbcb00e0441458b07253677d148f4850b464d6df7706c203d1aa", - "dist/2024-03-19/rustc-nightly-i686-pc-windows-gnu.tar.gz": "3135f03a8388c13c6439ef0464e2086949a528cee7bebdfb955defd59e55952d", - "dist/2024-03-19/rustc-nightly-i686-pc-windows-gnu.tar.xz": "54b6ca29f64e454189f27135f9a40f0bc0d0b5abf4d2912aeb857f733721005e", - "dist/2024-03-19/rustc-nightly-i686-pc-windows-msvc.tar.gz": "d3b70b07c8c9cedd30dbebfff2bfe45316752a13d49c9feedfdae4f71bb74865", - "dist/2024-03-19/rustc-nightly-i686-pc-windows-msvc.tar.xz": "653a821d9a7789e19fdd32f82466e906c23e03e42752f7277c05b692c1459e20", - "dist/2024-03-19/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "4a37e87a3280997bb09deb6a3617395b1e898ecd07f0bd5469cb21e55c3c5f81", - "dist/2024-03-19/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "a66bd9287cc958a61f9989d5efb6162255f7eb9211af9a4ea98769971350384b", - "dist/2024-03-19/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "3ce931c54c96c72034392efcbcd73061d6f8a7c7f40f1e86c14ae6fd5248d2a6", - "dist/2024-03-19/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "cab19b60b91cd6549f89398f46b31fe440323c9669606f48a4029e8d3cdc1ee5", - "dist/2024-03-19/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "3d50b95e8f9ce5a2721e1ba0649378e8426fc4ba531bfa13bd9b96ef627aa46d", - "dist/2024-03-19/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "9286d55547a438008574267cc3a067ca50005a9397bf8aeccd76ea27233de2fe", - "dist/2024-03-19/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "61843b55a45909408b3005cee338de42d31aef852155c8bcd8f6cf9aa3077dfa", - "dist/2024-03-19/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "2de14af7b540c3302e6b1a0f77472362429c0a1a0026c2fc799b263817e3c942", - "dist/2024-03-19/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "816575061e2879d6855fa497b3bbced57f3201d64c6649c89ba9020c69889fd6", - "dist/2024-03-19/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "58962496e51cdc60f9a98fb2fdbbb2f4124beb3fdbb065cc6b52871eb4bdc2f9", - "dist/2024-03-19/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "cd649970e9b8a98e9dd0c1f506624832cb08516aa9cfd001381ad265cc42ee66", - "dist/2024-03-19/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "1a9a2bcdd263a205bd85c8fbb9733711ceeee372953a7573420fcb55d59d59b0", - "dist/2024-03-19/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "98d6631c6dbca97491d5f518dceddc07c53aa309c7db8da0a919eed96f9e45bd", - "dist/2024-03-19/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "ee1fcc2a1d3181c2a7b97df8525363159c47b1348c0db78f74c7181ad6c44166", - "dist/2024-03-19/rustc-nightly-x86_64-apple-darwin.tar.gz": "c2768511ca6e9c228e13815040eb56f43ba1ec223c7753ea0e613400989a20d9", - "dist/2024-03-19/rustc-nightly-x86_64-apple-darwin.tar.xz": "6c10e9e824d1bc7a3c75172375e3490e33627bcaef6315552147b89b81ecf328", - "dist/2024-03-19/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "6d3a1f7c97fd4115b524f990426b795be1b9ca9a10fc6fd68db1cf4355d3953b", - "dist/2024-03-19/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "86fbb08c51664be63b234b82894b1b8012d8f6bbbbd96b6fc7188c22b887049e", - "dist/2024-03-19/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "39b673d694aee6c5d25ba88ba7e9f38b6264f01ed6a5785ea44e07594b9a7d1a", - "dist/2024-03-19/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "43ebc08539300d736d1d41af2306b1bbcb0d9e04795033725807d4c9c06d590a", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "cd263eb4b6e027b834723f3748139db6f1742f885c2cfa2a4842c23c806b48fc", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "22fc109ec6293b799fd52398b72f90966b9efb95c433f826e31f54fe643132cb", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-illumos.tar.gz": "20b01c262d54731c471d6dd856fbe8c9a58674f88d0dea19c7e9b7adff6b5474", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-illumos.tar.xz": "584d1e3b9e6e2006767a6a1a46aacff34a2042b4094e51be0a1a82a50a4ab27e", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "71b98f184c4b3f3a40c5ab7cf6bdae6947a39c2a7e36e590750a37806cd98a2f", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "44510c19128801a465c70fbb4d1fa0250edd7c1ff0a67f1c374f1d921e1a4bb8", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "897728aae12523d33bad792c4275512383ae5cff008860406882ebeb273cca5a", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "b027abf370ef289d6b2e615dcafac3eda20c147dd2ac4a3c113e8689f6936655", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "97360bb700ee986b0a36ac4ed4f0fbcf3c875907bb6cfdbe4bfa0274893109f5", - "dist/2024-03-19/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "e8414dc178f2d1939b2d6411beda7bc6f8e9b7f500ccb30fc8a8659ddc0f945f", - "dist/2024-03-19/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "8515050a52addca9d5c0ea8b9f4e5c536d32ed275fd0922cbe567fbf7d5adcb6", - "dist/2024-03-19/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "97c68112bd8f4cd67eef50c994dd13967482ac1e55170dfd11d8505c582c689d", - "dist/2024-03-19/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "b3ff60427dfa13e3c9d4965e0f197ac2a0625fe64cb1e23ec46604adbafdc847", - "dist/2024-03-19/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "848938bd1436276ba813104cde9d969cbcd79d295eb045ced1d82080cdbae29f", - "dist/2024-03-19/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "063f25121c6a8055228763240f178b7f1e9b55f20b305b8e2ebc1b0a080e432d", - "dist/2024-03-19/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "89ab3a28357f3926fa4880010d0ec6b6fce06476050f42c71416c60528490f7b", - "dist/2024-03-19/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "6ece90be16f59b3a5871d8cee8638e18c233eb0e59253875e71bd16ee4c7eb76", - "dist/2024-03-19/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "7272af79200e1da8ab80b2e4408501ef8a54c24ba44420aaab0fb03653933ad6", - "dist/2024-03-19/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "7ba3404ab333e43dbacfda6d8860d800721a7f894c672d3ea88cb88127128c90", - "dist/2024-03-19/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "bd4087d9e70c0246c0606015c1e6d6b974c068118e50e2720c7ac75a6d338709", - "dist/2024-03-19/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "f87c7036539d18881cc0ad5647b523dd07cd29cd38c36665aacbdb37de316231", - "dist/2024-03-19/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "cd1b05cde5ccfc389df6d146f467a18455f22c7f23e508537c8de11b8d7aea4f", - "dist/2024-03-19/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "66b0bdfb271448861ccc403d7549b49316c5cda81bbdaa396ff66c01dfb052df", - "dist/2024-03-19/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "40e3df123160c8948ed06c8228df90de1368d286f9849a0a14de0725167dc8dc", - "dist/2024-03-19/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "da09c72f472b6bdbf7e794d84990153936ad1c7d275daa75b506ab72444b51a0", - "dist/2024-03-19/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "c9e2ea2216c4f7737919c63ed0e5ca362f6c3c9f227f1b3e6a243a870f229a52", - "dist/2024-03-19/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ba468a1251b4bdb685cf5437222ccea45ba1f4d1b25ca65b82a9fae4ba93d6d9", - "dist/2024-03-19/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "64781d2017662c9973a22d322c92b242703a90895cefa584035b0d80ac966541", - "dist/2024-03-19/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "595fcdf3cf5b2511ec828936119334516d535c4dea95f60a04eaf1724a90a276", - "dist/2024-03-19/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "42f2537e87adc2cadee67e5dc1fd7fee4c7bf4347f88501752080a65b9e7fd89", - "dist/2024-03-19/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "3ecbee26e0b0cc43189dbd8d69a563bf71292974d0c5d313528a32012f38fb56", - "dist/2024-03-19/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "7a0918c6ad0dcdddac757c7f4580fa57ca188ff2edbf7eac07ce01626666bc95", - "dist/2024-03-19/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "08197220ca270180ff4d7f484000f6b7a52800e932937238cbf1f47ce3f1080f", - "dist/2024-03-19/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "dc7f03fa39872e59fab5f4d663ed092409849c62c8e4c958c6cd4ed59bc05902", - "dist/2024-03-19/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "c7744b4c88a5ac7ddbaa1b61b66b39f2799863c50b6e18c18874d5774d11fe53", - "dist/2024-03-19/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "0ed8aa4704e7d665843ea1ac532b1631cbf449180331d880466fc69483d4cd23", - "dist/2024-03-19/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "e67d83663cb54168fded400385a5cdf8b74c6483d91fd16d03846a6411ab1afb", - "dist/2024-03-19/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "fe4c2401281c07d1c3ed335575bd192ac57396973a3676226d57e5de32a63e3d", - "dist/2024-03-19/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "39c4739ef0281bb1eeade5c8f7360ee8dde5a8a7ae148b0f263ba650d092cced", - "dist/2024-03-19/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "ea26063a71a4403a4aa49098a96a29b48aab5f9b9177e57b1790b92ed749ae1b", - "dist/2024-03-19/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "49591c34bcb82d6cc5c08c662c4c89aca07b406fa1b48b78c7dbcb63cbe6fb5c", - "dist/2024-03-19/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "df664d781e8104015c506178df751ba7130c677f050cae695428fbb6180b1af8", - "dist/2024-03-19/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "ff20c34ab85505c1957a677eb8123622c98f5e19e87cfa38eae76232e200242b", - "dist/2024-03-19/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "c4e8b76738bbfddf94defb88e9b0c0d0c488d9a5868f2be629322c041391b43c", - "dist/2024-03-19/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "8e0367ab0700e916956db6041e1c6a35b0c6fbd1127a17f9482691a103dc8d70", - "dist/2024-03-19/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "1aad45bb09a907effb39378acf5c57c741d7b0e29eec957d8be31eb1bf47ab23", - "dist/2024-03-19/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "f5fa93652040ba991c429d11c5e9ae2e76aa6f21f6850a777f2ba1b065e943fe", - "dist/2024-03-19/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "7d448e8ae9090467197d9bfc7ac3d8f7ab81cfdfd0be140afdbbbc6c3cf65295", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "8ea5bc3f374b5b63432151541715ab41d00f265e6cc8e57c61e175304363ca5e", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "666deba3f55f30e302642b3e2d3c86bdce12626ae78bb7134c7d90b1c7179592", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "edf75305baace32ab2955131357e30c73c736d823d6426125e5fde213c8f4c61", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "5b3ebd05d571474002c032aa2fedc788650d374b388eff9f6c00cf5bcdd10c08", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "e795bb7cfde3d71f9e964dbc9efd930251eb3209686d5c9348f24deecb01fcde", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "8e1c06e91fe7cd1ffa80f043b8342c611d8f923cc9b563fda0155855d8799660", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "a8a51ce3eceed87d192701abb699dc60dd3c28c86622b9aa3dae833feb8207ef", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "389cd5d4c0decb87eb24b9ce88d5e5f33a7292153e2eb37ca2a106e4f8a4e256", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "cbbdca68aa3ff10fb28d431ddd08b56bb4f0a0f85ebaf7c094b9740c8e2d1aa2", - "dist/2024-03-19/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "e1c1793bfd102241338f801ba8c28f83d15fafef09046b231e30d1ac42b5e372" + "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.gz": "5a8c5e48a88e7c7b41eb720d60fbd2e879b97639c7ff83710526e8e6caaf8afb", + "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.xz": "0d237535ae8d435d99104fa5b9dbf41878e2304bb0f2eb574bf17dd685caadc2", + "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c56733bb6198af0a9b0df9a44ef979150e00de33b70853c239cccfcce23c328f", + "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "7da5f887151215ddec640684077d98551fe2aed75a3ece2c73b20698754a70bb", + "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "73851e304a539d41bedc0d8a5d98800c8279ae623d3e58e863f8c1f8b458b01c", + "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "db9c28841344b0154756e19a21795ef6e0c4e27c7844be9996824f1039edaa81", + "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a706c8c7e37b9e80d7faa000c5d179a772746eef071387fb2879fdeab1f1f891", + "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "2060634afe1b4a19bae874c6ce3cf4256e613af26e06104b45da5bd71cfb133c", + "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7af61e74faea669fdd41793e4b88eb6a37bfacf845af364ee02bb7cf08c612c7", + "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "4759fb3e3d89ead605c4eeba23be5cb9b3ac98086a9de20f8dbfdfa9282ee486", + "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "4cab18df2d94702e8b551357373bcae60d1023e644148f0f82e8971023362121", + "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "7de4f0d72b4e5770376ede82b02d6bcfd450788a40375fad34d75524c941d72c", + "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6401391a426cf33d6c58f07e7b2828b178720cb4f2b8577ae932b5f5b7d6744e", + "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c3f6729bc769325046f0f62c51b5bed30068c37dc2a36a6283e50565d8cb7d5c", + "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "d116c97c1242220c7972b63010aee1ed36bf5353e84a06d3561cd5fe9d7dae84", + "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "65eba577f7775b3eef36e7f000b5007264392b20a7759f8ed567f3a45b2877db", + "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "d418a3371b3631328bde2b1e0c3159700f12424e83b1d8ece1349fea90f9e403", + "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "23ae73c776fdb0795944656d743444e3b4c440f45084028206c1aec52333b1ba", + "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6bbdeb7c8bfac2e8a083adb4782caf5321799f47acb4eaf81da32bd11730e9c", + "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b409691da6ddb8c04409667b2c3d9d6429c6b5bf53ad18177248406a5f06cb9", + "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "24cd888d14a788e8fb5b886735f3c07a028a8681df48a777b2bb971c62a175ae", + "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "e8eece6412936fe4dc863a5e19e6766fbb20e81da0069ad7831465e638db23da", + "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8f007a2aa02e35c5ddb2152cc7589092a0e3083211c6aa23e676e3a3ad5a4b8d", + "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "3e423e693dd0813f5d87d9eded94894076258ece56684f3598321cd013aeef3c", + "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "2eec5e45e389a52b526a5cf683d56a9df92004f6095936b16cd8d7d63722cc6c", + "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "64c5135cbff9d4fa9575074c55e79d85f72cb1783498a72e1f77865b9b2d1ba3", + "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d64552a80ca386728e42f00d7f1c700b5e30e5a6939f32ffa15a7ce715d4c8e9", + "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "fe91adce8ba35bf06251448b5214ed112556dc8814de92e66bc5dc51193c442f", + "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "77aafa8b63a4bf4475e82cd777646be5254e1f62d44b2a8fbd40066fdd7020d3", + "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c38f0b4adcc8e48f70b475636bbd5851406bba296d66df12e1ba54888a4bf21a", + "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "c05df24d7e8dff26c01055ad40f9e81e6fcb3ae634ecc1f7cc43c3108677fa0e", + "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "47e8f4ec4d996600e60ddc49daeeb43d4c21e0583a86c12395c16eddc7db76ee", + "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.gz": "f024bd225b77160dc2fabde78002c8deac5cbb9a35345340964c3b988b0d1791", + "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.xz": "96c9e44bd9f0c85c793e3dd6043cc4f89fbeeab5ddf0fdb5daefca8f690bce05", + "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "517889f222b62150fe16bcfd3a0eb5f353956b0084d85713480197bff4558145", + "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "a6653ea4aec51569c1300c044d8bf2517a1f5111f710d12cd352190425b8f317", + "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "4cb5b5054dffe6721efbbf29192a67e59cda69ea4ab4791aaec6f314eefa5a5e", + "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "08bc45be22e9e4f615d1c9e70500046c8db89045f5d40dcde853c610591712a7", + "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "9661357ee8ea8973016fdbaa2de3cb98713136dcd25f07aa9f9d101180276815", + "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "7fab806227d1a3be817602abb121ac7e039ba0bbf81e0a1d47bdcccca74203c6", + "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "4c79bb48cfe64bd38af7fe3660cd8bdc99ec90738a0d8fdf80843ecda910dab0", + "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "0fb9edfdafde1820ccb25c22369cafb0e75e68795effeb615cb284a5837c75ba", + "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c1902a072e61ab5ae9737a1092732e3972deee426424bc85fcf8702adffdd41d", + "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "d39ea1195dcc95e428bd540abd2db5b5d4c997a7661a41a4c0ca41cbdd18d27e", + "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "0edfdb6f6bb2a4a1a96a5e95cec897c444c936e6624bb4a530ffed4847b97445", + "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "70c264b7845febdee45d0c6e44b65d47ba7f367ef33ec906a9fd7f992ba7cc13", + "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "f1bd6417a54f3b53d572ce4af799242db7c11265c71201cc09c78d71be38c13a", + "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "53569810469c483785333759f86434706ee5368d5e18270ee13a17817ad57d40", + "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.gz": "7b693bde61a090854527a145455ff774314c65ec0cd47d25a19c76c6a166d96c", + "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.xz": "2494e9fdd8d342b6bc3e55eecfd555c43e3cca8421f3236df2d5a366288fec62", + "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.gz": "90307f09c6fcb0c1fbe3ad1522a5381a17e2f69637c6d00f4a2cb5f3149bf736", + "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.xz": "f7e0dec4a4862bd85d894252366152b3b6a7627e7e5a25ce323fa2db3bd87c2b", + "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.gz": "7c719e38f2a1030ae61985205df52f9a0c37b659463a5e2dea8e60e632de2d73", + "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.xz": "181ff4ae6adced6522a4c29869be3cc5dac8b961c7c88f2957cd31f831490807", + "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.gz": "4e0e63e6f200386995e369a2673867d1bc3005d51d6a57c00ca80056dd85316b", + "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.xz": "3d5b22a13aed6821482e60d9cc8571e2da9d95d82104284b77c56985a35a9c4e", + "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.gz": "9f788db76a5d55b3ecdd04a70b0e2be466959f76ae9fd3497ca2c503504e0c03", + "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.xz": "f4d8fc103807fba61d71d88b8e25a7016bfbd1a2905330f9a9fb3d7ba082713a", + "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz": "d61bec3d017dd0be43e48350190ad18c0a0269e43d964600b62e1f7fd4f84399", + "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz": "c00cbdc41a4da0c313a1a282b0158b059dd34f640b582cb7ca18e3d290ca8fa5", + "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz": "52143a530ca5274fbb760beecddff16f860ea787443d3dc708dda7c8f32ca9bd", + "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c6d2dfeac6f40811bc9b4cec3c23f9c3bb46f761e006257b9313aa7c1a647b5a", + "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.gz": "325d39e426b1907fa17d93c0752d3d73bd95750f4f967c2a84aab2c5dac8a588", + "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.xz": "536f591d4da455302029384ed196932d71119ef0160ac5415617d6b777c51123", + "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.gz": "c3684c9bf471669d444853bf484880d17e150ecb0e7505de90883382023e343b", + "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.xz": "0b00e6132f73d5dc762e359b0005fceab0cf7b01337d8f4aa9eacfb4552f9245", + "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.gz": "c91c1eadfc4cbae360a0eecf11c32d2509b68aca86c7b1de3b102944f43e1511", + "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.xz": "6f7a5a287dd6226c203bb674ff02ec773e5d0813091b2af744b88ecd6997a304", + "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz": "58383f094995823ea6db6a87b9ad4b33bdae2264d29bab88ab71ec60ccab3b93", + "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz": "dbf4680a6fd4dca54acca5503a7fd94502b8e85819bc02346ae9cecd275e4514", + "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.gz": "e28eb32cda42654c0f0247aa8e15f01f73770b36f7626c8d6f1b7659accc56e6", + "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.xz": "fcc48a83b748e1e46f9daef40563f8e5abbb0e3f014a168b04f3c700c2ace2b8", + "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz": "b626faf3275fcd196cd627e8a36c67721bae16a56f61cd080c79d137b3ec7737", + "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz": "2c599d2dc719d69f67625f3c6573fcc4f1ea3266801557dd3892bdb7c761b4cf", + "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0bc1f546fe0cef2b9516231ab608de68d55f72022fbc9ced5101b600e005f8c4", + "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz": "993294f2ae5202785ab242c1c6567df9c8ab1ef44ad35748c526b7fe854fb94e", + "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz": "210a4f0d208e0c8e13a57fb3b3e6c98ab5f620e4988d10a127ff1424ac1d5ca9", + "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f10f7df41a13ee2ecdc25d60e697cba2342129a912ef20d8bfca5f611a9ec97f", + "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.gz": "3e24d2af65f0c9667c9997ce091711b2be48e673de3707cddfd8cda455dfecc7", + "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.xz": "0e7b8fbd0207489e38c78c2ae1aa0df4fcbdd84741aa50a86379e4d7ede286b1", + "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.gz": "9c0c47fd97ce72abcd6126315834c62aa7297fe09d447ee4cefa1eb46a116326", + "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.xz": "49dd65c5340fd804399edfa2402cf255fd9bfce1f4aa7fbb3c193c11bc03f8af", + "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.gz": "6c1c3bdf097a1846ae08b098c555c0c5e9e9b646c744d6bb5a855789196b8bf6", + "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.xz": "0a7319d1062f73af1c8f0efe6ad970d10d02259162c5bc84bb1f3a10f3911bcb", + "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.gz": "52fef3f8a64fa58934a633bd4944e8ba9e15f2c2766d0f302dea1a6523864dab", + "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.xz": "8fdbe7590e62ab68a2e463b14da2595e8c4592744f578a813f64d430ed7db4b6", + "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.gz": "509bf535622bd26385184ee0c17e4e27a5061a8aeebf5759f24bd578692b2f5d", + "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.xz": "2fcd10ada329ba7633616bebc584dca13f11c465e7cf513e76efeb0c3174486f", + "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.gz": "ea8cea0d4a2379bcd0693f6174b25bc1f90a016dbe8280159cbb61d859806fb0", + "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.xz": "5a243df8d1345db6bd18e4386ba628e6d302bce1cc572fb447cca4264fda3ee9", + "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.gz": "2ee560d3c1e306e103eb06d8e8033cd1489b3f6ff9df3bd8a95e25e977befa27", + "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.xz": "aaf6e54184a65ad6592bf03955a84ad12b561afd86064b1ac5fa03cf637052f8", + "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.gz": "1b3877424a0a0eb507675a50e9d2c793f00ab85f6f12b1e27f871331070325b8", + "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.xz": "6df5eaae5afb64557ba5c3a53ee3e56dab85455838a6044c7671c1180acfeaf9", + "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.gz": "1ac05ed7b607fff8b77ff203a663e9f4f2487779bc25e2dcd454cdf5b7583328", + "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.xz": "da502375b3cee8b254ab5999809f522692c2d1d90ea0544ad03c0ca514c65ef4", + "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "2fdd35ca3b3e3d6f548f11c93337f5bf2e3c088bc78a79881e6f8e230b38b9a5", + "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "bc16b3a1ab6ed69f0121a117c50cbcd201500dae4d72ad0dab148913d04cc529", + "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "9375c786703c17baae1c2066f8d972ac316bc840e478ecd1b94288a1d428324e", + "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "50d6818a8dd3ab7a3ddbbd7a062b538d9ff3ceb6eada031d1c22ab1dc7ba512c", + "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.gz": "56c3a01e8fd5c2ed75df811993b0b724709fb5473cc308ac09e7f5644468f751", + "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.xz": "3527d1f2c99c806479fb4b3801335dc921b514f171b82cd252cbbfc9ed30b163", + "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.gz": "bf8cae7c66489f1aa27f1dea1b37f0d0ae514a6e21b93ff2dc6400dc88feca03", + "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.xz": "46799f0bc1b3c13877f6cb732774cb3b33e0d8a081bfb56d0f877e79482aa1de", + "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz": "9f90fadab5104e1d415edf3b4edfaf7222f9f0d55f849851efdec74ffee16f8d", + "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz": "87ed6774202b18691bd6884df6944c7e9fe9c944b57a2837e7a7647518bf94e8", + "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4a0692ad28f7f130b472ffa4aa766b745ba01fb75aa921f2da6622c9c68750df", + "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a3d45962489a1e18a87e567cbbc8d3665f38809d0ad2ef15bcf0ff9fb9f470a4", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "c724f4eb135f73b9c79618f27a1ab35dc7b9d26ca62ed796accce68f9e747a66", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8eab25782d16bcee75f86ecbb826346beb4a7525b220b45b3ba05a567c6d4391", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "33ab1f8410edf590570d7468dbe2ebb5a0907125bbc8d360a928dcb355f0d0e6", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "d3d870209a55ac96391affaa347c04f48cf98c089ac5056f340b8bb38bcc8e60", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4d2bb72b898c30a2fc8d5d3333c2e99a8e30c15891fab641b6a519dc9f0cb611", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "fa343e6b6110fcd0c5dae4287ff1a799de5d7e4a805dbf4e9a034bbaed2bf269", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz": "f1ec4139783169fd83e1b0184518ed25d26cee7b21f196deecc74e83a1d78725", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz": "d100be2f6f0346c4b1f5b41aec0c13a47426bf4d49127f2341c8332903e4e782", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "bab6051e1071a58cd126580f6644decf16edb4473fe4be6a34791610d820a294", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d9b68f06ff23629063e92dfc42aa3115a858238d368e4b52b35c1ea4491b1402", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.gz": "96804c2d9accd3242bdc22dad688b2ccee071952477b9c592f099377aee6c591", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.xz": "3fed6812d84bdaf787e85c37e23ba729b81a6d25a2b33fed75320e66e6641c89", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.gz": "8da5f301bff35fc067ec7cfb878ebfa5607af7dbc276a6b34a77404432c700d2", + "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.xz": "80d643189dc9af98b6410a01261ce6ad34b1325f3aebf3ff61fb43f1261b41ff", + "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.gz": "2e86b54b0d1f7fefead11d6383bdc80fe0a7b3ccf58381d2a731e6f1c62926de", + "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.xz": "9831a0270457cad2798b5ae4fe956c257c7e10ce5ad211793dc467577cdec29e", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "f96bc303c0c2be9cf589f00aa63b2cf3fb8585ca9dd8860fe525821bfa1fe19a", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "e57a053b1c2bb6fad93dfaffedce7f48fa292196fc8ba6fd2f0c74dc810a13a9", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "49b2cb2ba5296871b5fac5ad9a74a2891e8b78321078a455ba4a65e003bebd40", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0f9c15d834a9d282a4018934759f7b48ef3d275e09679a68c5fd1b3f047d02e4", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "e59f92827241e670c1aa92b35235ad12340869d59327fb83084b5f4149acbe06", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "ad1cf96bb1fcceaa016e29e8ad34b4cfd711d2e0bd7cabb9cd7cc28abf64d894", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "14a6d318af85bb9fa5c229e45a88a32a71f44ed02cd90a24bb67921eb64dee41", + "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "ed6b48502ab9169818bceb300b4e6b4fd63366ad5808b047bf9988dae04c2729", + "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "345e8a023be55e3b88a0c2677ea28c7bb4fcc5f3ab707638de76065c7592c2d5", + "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "6d9b11d08f2d62611327a893b45ba07c36df11f077250496ab0881eb7ac84c65", + "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "a2ae1bf003a8a12b2ecb6bde9868a978820f184af523f0e4c3fc935edd509423", + "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "3d1dcf8308f9d4590b429f6abbf8f42f04496ab490ccf4ed8c9e381e6d886cae", + "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "a54106d27e4ce97463e7867ceff9dd22ba456f840ec23229e6909b37d48ad554", + "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "e6abfaa0905a00efeaee85b9f93793bab93e2cf4e172c9d829c5ba85006c688a", + "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cbed18e5dc61fcecb2920affc3890c3b8ae46b7fe5a80b3288689e18d490f3f4", + "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "2b58bb0dd5cd2c5f7f93f4c6e9135090b931e0ffa27ff9efe2b8ff9fbbb7e48c", + "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "6a371c2ececd349dfa76a02563069912fc91577ac4446d36c22f96723d7f5e9f", + "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "9325daf41ddab02fa845971c10a5e0538a18c7bea14e66fa0f5f6fb16654c7ae", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "7f5ba76cfb7c85333c8dab76fb4ad3f12ddc254b95f9ee07fadb8e1270a4f767", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "f853b7f929b7a309ed6c08ff8c57d583ce0ccb19270674fb30e63a873834dc87", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0680005d0a12498b687afc583d4f36bd67d0877cd9d3323bfd2df50d15c27afe", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a494b78fcad01c83df9522d460ac2d35d2d00736a921381f2c611dc516edaa16", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "cfa555db31b5470e878b0f53d86617e7342e8bf018fe62cb0271dfe13db95f51", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "0a8ccd6d88cbe79a855111fbda45aa1a728de655b6927f3d429d901d2afc6503", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "eac53424001c884a540c42f0b68447349ec5d0601a030c060aaed76d54895728", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "42d78fca62361ff28db5bc43bb01cef7af5c6f4ab2110fe6170c3dce4707aab8", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.gz": "c88de9f2e667da73177fb9c9309d7f1f467e31c18e3ae50d722c71ec8dd876a4", + "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.xz": "24b3c04a42d511cdc8c6107b597be38981114f0574eced493d0e90fc748094bc", + "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.gz": "cd4ad182a098c61550265879ccc04733c39110827f7ef62eecfb8c120ae4ece8", + "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.xz": "8499a014dfdf448f474a58f148784c2eef245dc909587d876d2fb9ddc6a4ec3f", + "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.gz": "e8e1870e5b12b3d8643d712efb91eb86b2081284cada4a140c1526692ab183c4", + "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.xz": "d6029121eacc44bd4dcd9ef6dd3cd0d775cb6e9a3d99f3d62d746fcbf8981cab", + "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "1e0fc42c3802e205130c01ca90f92d793c1c5427b34da66fe77b97cf67b4a5c1", + "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "4c8cfdb11bb686111fa4842d13430c86d9d14ada30e9df334b3777fe899233e0", + "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "ff895c1b39b84587f10903f4be13d275b545e690da6761190d12c01acc25c6d8", + "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "fdcbcff7b740235bb16e44174fff9080a7c0a31be358c8abc41805c02c20c3b2", + "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "6b227f3b9001e148b66b7001f753a6f88fef9677e39d8fcf4d9c35fe8d345568", + "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1e29297beb8de3778ba958731294823d9a93aac1e0d8833abc5aa99e2935965b", + "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "26481ad5f22a319830d42f69b1c0195bd65900ebe112e659432334b3468f3d0e", + "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "c8a837e0d9da8ad976fc1539541c085365aac9dd28b34e4a289d38a823d1b065", + "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.gz": "f05e28a52f17e22f36ffc70018012a1fe6a07f4b461e774b36464f32bc8f8dea", + "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.xz": "f9501b2691c51e54a6f4cc6fb72e41901eb551d3a7be5f82a94ce2d3e217828b", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "8d9a782d4f7450bca536aab45147c6ef08bc3847b43fdd171c6449e29762eda0", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4008712e03fb6494eaba3d79051c5e3fdd93d4c52ae8d86cf8f344b5f051cbca", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.gz": "cfb23242e495834a3d0f7ffa3da4a0b206dcae35872b1455b11faeee5511ba5f", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.xz": "95415742c0171945ffc2b67c913ebd1330e29634af238f5ccc843a965340374a", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e9354d69e39ecfac1d2928664d17d73f808256a4076b849171a9667705c0aa08", + "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "a34bb0a91170d84195f35ba52afa4c9be8a2f2706dbeea02bd6e8908e08ac65e", + "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "d65f286de399ccc9e9acaf7a4dc4f885357c750231d54a144ba9a59181814f11", + "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "4c93a7da70a69b2ebbac01df64af16344e523d16470b29e57237b1d0925f7721", + "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "1b978bfd1a9234be7ef197c8c98c5a6b625f6fbb7b0fca58695986768bdca176", + "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "98d4eb5b89a593c8c4f86244c9a7c737d9c18c0168aebe5923b8d9145adcf89a", + "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "dbf9b3c5b54b3eb0727f976f5632c5b0fcb2f90ac7453962d6cef20f7dae4284", + "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "f209ade093753342dda6e710ee832a538dbdaa08a24d606f9a2a1bc59b83da29", + "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.gz": "3c3ca7f34569b2c70c6b223754418a535dd7dfa087ab6e28ed2ec78d20065887", + "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.xz": "72a7cd0f430ab40d80e93f409b8e26a181010ab4bb75d151e829d51ccdcf8c62", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "b7dfa59bb05cf806c87854d6fce5ef0f160697052fdf6e5a0cad121499108608", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "88bc22f68bab3367cdfa91676418ce1ffc0ec002afb32aed7def880bdd4be402", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz": "d61019048b941064a99d19e46ff3236a88a2e8fcfb963cedd1d9d1c47963c170", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz": "7474bda08134c676d74afe5263317af3f271963d8ceaa5efbfa1b657f885c572", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.gz": "e089c77d433d838ca02d7531d6f4a1770fb4a0568acbd96c8f43034d76f2990b", + "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.xz": "364ae6c89c7a930098286e55193d2f5ee3d5ea80b7cca73046e41725f4a8a2f9", + "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17bfad87d16f3a8d26646525dc59a352718db9e7572acb583b68a18cfdc338a", + "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f5c4ecef1c08d19ba6fddbd359a0ce94e46888021cae057fce969276026d086c", + "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "3e7e13b0d2e804d228e1e3a9dac0205d294ae29dcc37132f15fb1e218861eb39", + "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "ea31b7678e6f64c2f9c28a9af120be04ed6f2a25a496e40afbf6e9aa0dd20b60", + "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "f0e1b314c3d5ad1676c68c112581dce62fa06ad557cd5f61034e147b064ed270", + "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "8ab7bbea6e2f72df1286facc7d306d01809a4dd9f8901dfdec7e50b594658d49", + "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "48f6abda1c7dac185858744aa2cdc3513cdfb6552535282ee83cf9c5365573c7", + "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d920d97f15b56ba6ea81e08b3c29dc7f44f5f30b7513c53446edf95843c332af", + "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "0a198a770f6e6043e923b0ab1a508fd8b190612d0370c33c8dd2c5f63b6f19dd", + "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "424a93313cfe2d85acf956be3d9ac71ea8e34ee61617a550ad6ff5360e1dff52", + "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.gz": "2e2b0a8e41f4ea774d665d6248cbc2fdbe3e582206efeb87d250786ebaad0b1a", + "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.xz": "2da372c091017b7096e473e5c7016a504d2e041e14173d2520086cb43e0a615a", + "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "69d3b21403181b2df14243816388169db2466477ec34bcca5693fb017703686c", + "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "281b9c20f8641a3d1b349e762b7f713fb0b91da0d21eec798e639e36a0ea3dab", + "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz": "dd9bfd3fd8446d35180fe781139dfb4e04dd658b112eb2a749e8f4aea14f0271", + "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz": "b1366375e0c5f53da581741dec91972b0c46d7d466052539207e8feaab0ba3ec", + "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7c6650d8cf8abd51547010e8211af3ef3195099ef43a563460ad4780de20ba17", + "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "bab46f3c0078ce346de563bb7a248ca92f15dbdc73bf5a3bc520486118442320", + "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "01735b4ad5bc0a53087dd0ccaef2cf174b27e45bf4d2e3c15e64f7522f059c63", + "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "0bb272c2c235583ed3e9ec151b3bfc601f8cd07822c2fe47a1258b358be507f0", + "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "b2c7f8ee0efe6d0812e4b5dd0979f60f105b84d34d4f600ef75f2eacd954893d", + "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "0d5301fc553a6911af6643ab7f57b6438bf649ffcd050d486278c0c5fe38eeba", + "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "0d1d35ecb88ee717720ad8e74bd5b602fd6011fe321baddb939f3b161e9cd8c5", + "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "a5cf0b98596e68e6f72be2e83c61b8aaa19ead42f248ee2408a3b8f4e97a6657", + "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "629ed749cdae110668ad9ddbc5c61e99e8d400f3dd0981146c3820deadc360f6", + "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "192819438ed27a565cdb67b51d2f5caeb6ae258de86191d6922574327f132acd", + "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "84286f6cf6f00f3c92dc881f64a31e1ec5910102d8d3d4faf6fc7e2ddf1544a7", + "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "304b5f876b47dcbb7c3483c49295b822e8ba83234bb568ce67896ae4773ae2fa", + "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "25062159b859e21dda76ca22d4a31d3aba4fcdb0def78bc5b5cf9887c07c1be9", + "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5d557ee86457f288462603fe53bcc2e092d84faee543659419fa68c1bd88f554", + "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "a9663048aad82ef832b2cf82fa9fb94be047f77e283e8aa3e2df6ad957d0782d", + "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4c4b703a846b4123d09c1eace6322e82784a004b278f1f3b1ca1279e96207f18", + "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "32907c33f240abb1cb17ac438da42c5fa3932b270ad08fd6914775c5b59a02f5", + "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "112583227d2b6abfef6eeb78d980bf2efef392f3b66e433c4959a642d72ffc7b", + "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "7ba0084527a18479c4b6f6a0dba8ae23a0ed50e9fc5fbfce23cae1babb5a1e12", + "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "49eb4e2efe3a76713ce1fecacaf915717eeed8552912b92895c7fee068a85a36", + "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "518a532b52f2dad2825158614cd00b12aac6c6e1983a1ad53e2b0e26d1f1b845", + "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "2895e5796a29fd016462694d880e38eb191cb92c9bdb14414c1d6e63b23d3394", + "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "2af590c063344c4c3f65d704fa255232b5f5954872d03c4c55d48662cbe6bb17", + "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "a09df5f38183d9fe6116c807619f812410763ddedf06055bfe8040b5794104d3", + "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "eac22c4972bde3a57cf2ec4e31b43db3c4b7d961ae31475d8942e898c07640cc", + "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "104f2c6490e30cc47833edbd806c2efe6256d1194600b2278339612f94704d45", + "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "b3c9c9d7ce8c1db6f20e8ede542e67aacd6047c52882a5d06c4f96a40a7304d9", + "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "76bfb114bc7674792934a4892d2db41fdc8f5bd30c3aa96c43e8055199157476", + "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1308335fe80dcafaba511ee589959d461145533de5f76118fee29a7e9a15841f", + "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "cb8acdb8920983c03b9495cf3506a3014384b4d2f6a53e7907924d38a0baf7f0", + "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "9dd2e5ce7534ab4fbb93ff652196e877f4e9eea3863920c3d34a05d9a3598c81", + "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "4b6e962facf7c54846965a8d6880e4a980804459151f2e22ac5af79bc79e26bb", + "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "731603392b6e3d36b3a4956928d084e293ef18c8b8593efa756e753a2a309709", + "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "8b681b3af47855eb63c4ffe06a2bc6bc4f365354ffbc171ce8cbd8c2a3588a07", + "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "7b87e59391493c3147c03794061111e25bdae669aea58190a951cdef111e75e0", + "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "d15eaadb101027906c2fce15b95a3f820bdbc4cf145b705bafc2ac5291289c3b", + "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.gz": "07390ec742b79ec11b2c3ec65f60efe5d7c616f50c33058fce346f6e9ad21af3", + "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.xz": "79e34d46621c298cadb98c00ce3b25d97474aec300d85255153b47e21b7bb744", + "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.gz": "b916dc9051b0278f820ea0b093db3ecae2e27de641ef67a9b508df75dc92c938", + "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.xz": "2867922a39da3b02ebdb93fb78b010695daf468f87485ad8ab79c7f3eeb18b11", + "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.gz": "792b718c0a72e97ba85a17ba67ee09e55b85de829fe4021f828ce54ff8cb31e0", + "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.xz": "abff86499119bddfeda9059004549941dbcd3d911702d4a9c198b94f60e60f4e", + "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "0bcc7698efafb42a37f20815f5660e39829a42a2776304e7129d0a4ec0c7520b", + "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "c437626e250b0d06c05dc828ab81d0d2c543ffce4b100567910508974ea50045", + "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.gz": "7c98c9f491bfc837111769a45c10ce2f1ef73c22377158ef9ae80b38034892c0", + "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.xz": "f4bda724e6e382e02ddf4e4e7a479120420666a5a1ad3c87a85d4d3c763f2cb2", + "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "01efbb2e48045318e18bfc7b6c190b461a219e81fc1cca6c855bf0c658aef556", + "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "9bff316c6d2fbb3c0889f9ffe4eae496b293fb3afaf8d597155e6badbf0c6a8e", + "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.gz": "5da713547a8af2c86da7db5d8aa4c27188dea1089fded81ffbbeb0f78952a10f", + "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.xz": "9d6a45d6af395360c63ce97bcfc2f9a2967c708afcd979f17fa447239703a92b", + "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "d1a71110bee002c8edfbcc00e0f5eede5afa005b09944bb2cde469c658049e70", + "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "6b8d18c83b9fffdddf9e55c807dc7d5784cc6d7ae90a57c29b87d707f0656964", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "28921ee14426f54aa09523547516437130654b2d9814120d286f209666c88533", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "7c3125cce30978ca2619e9aab150cb5b9b2535fbb6274d4ac1b1d4342c7b0220", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz": "ee5c237f092f8a4ba797c4c7769dfd4da81b5c86d2f4b88704d127642d222a22", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz": "30c84b04bd2d4d33abf1875cfee5f227ef6484edc67b3cc4c9c96d92c8406d6f", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "81274050e72c5a8ffdead83f7be62434f35a65517a1b3c6f7d9d14d0d59da710", + "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "215e20c78a2a4edf9b8368a29a09af5f4cf8d0edd1995de3bbf2eff01127cab7", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "340131cba121827a9753e19cb3a4b9ba2ebe30569fb20d7f9300b4dbe2a15cf4", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "69626178bc5309afc8a02c941bd77e70e1aa6917ffb6bf0d67a57d921b5c664a", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "22c6c90533dad3a731ad8a6696e6cdc1b15579e25c658fa2b094185e1893934f", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "30d7ef6684fa98e28037b69d4220cba40489c23e80fe7793c98b388dc161757d", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9d7192d32eaa6b6ccb0f615da0f4cd80827ba6484eabeaf401d8217678f1e313", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7a3fb35e0bb252d5f90773136d1417c26d5601beadb77d6da6f5ad3081977f07", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "e987635519c1edc8a1d147ca4a86283637e4dbd0a49736b01d605e45a3a14e8f", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "c3ab6b97dccc0038c68494b03b6d444d534e447226a2b2e140af54c94fca0b2d", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "72e8113687be8f947c50befb42b0957dd564f01693cf4d68d749a9e074032ada", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "867b24f33b19f40727c71818c8a002718d44d4cd4ceca44314331e19c1adc1a4", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "f9b0fd9605bd4e264f5303bd740d9a0195bc147132969965b221f9da0d7875bf", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "022dcf4887df41d776ba2666858b9aaab479758134a71f7c6b2172ed7c1a1752", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz": "b5ff4a0ecd7e0f71a9557b6096bb907e5cbc8982431f0d9b01d8e1a895d8b37e", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz": "e40d5bfb46aadf6faf849df548154db3f35f356f8b98037a056802a235922b8a", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "57cfb1fa472dd9c01fc0caf605a55b7248375d616acf84ec12f6430d5e07e2ee", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "e4121f060b917c811d971e85ce02495e83150ddcceb2204615edff24bd55bfa6", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.gz": "d63559803c8eb47e0d10d9f3a2284477b570a2536bb541762774271451e1f0ce", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.xz": "5388cf8ecaa234d507e505e8c6d433c5de8811b2717aa254e4caac9f4aa6cd97", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0f027163f37618df4330ecd82afece432b0a509ab20333d7b787c0d139ea89c2", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "b1c722e894b145c2183183fa58762c64402fac077419dc7874f8b08eee665651", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.gz": "24e2ac0d44619ef9b76cb1af6178103d65ab12e2677b366e8aee0604798fe5f1", + "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.xz": "1d8a45f1bfe6650edc5ddfc8683190eff5a74384abcb2f73eb3d1e88d566ccfc", + "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.gz": "ea113c567692d54983ab6c376761651b6dcf9bedad5b5d822d28c0d0d0733cf2", + "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.xz": "e36363f1ea531d2fd563f471758e387de37a34e7ef6f4c12175979657333c5b4", + "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "52d77d540fc3f83d82f35f358ccd9055fb75453af3e3bee4b11636742559db13", + "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "843c56f5431c1feda85ceaeef0daf988e8ae020b3556326fb1f75ea7968bf2df", + "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "ba2fe37dda1a487a2c75151895f4f6e886e9476a992272ce26e9b5fd7adb11f9", + "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ccb7be3935de1920509d2061d38f92f1fb8d2a5dd6cef392492242a929363fa9", + "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40636e0936bd311803317825c5fb6b446cdb5536ada1db097b567df04a86d7dd", + "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "804ef68f24bc0ba5150177d8b8515daa54aa82fcb61472385ef1a1d897c5c3e1", + "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "a320c2869d1d2c92b698397d4467c8498cad9481f38d28ac810bd165399ca46b", + "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7ce92211d87068d9c223806929adc34ca611a1321cd58b5bd81aabb0ec3ff085", + "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "79c16b902884301882d16be36fe75ecb32a8e49abde0038ce21cfbee883c2c3a", + "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "9384eb9bdbb585b414b6c04c592a79e90a0c0ebfeeb970e5e1b920cb638807cc", + "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ff99de5b819a4fb9adce9386a309b9841bd33632eb7d5079415a6ca6fc86b9dd", + "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "55635cde13af11dd8cc007d2e0499bfee493bdfba87b6efd7b1fa4115f5728dc", + "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "de82ac745275f069225b84574ed145afaf9f54abde5246592e49d5d1cf40cac1", + "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "a8a7bf64d33c95a2f94265fba8dd9ac50bbb727f4bc3e79be5bf61212cb5d22b", + "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "88967a99c993d6e0c3c7948308510644286ac826266dbd3d89aaa083100711db", + "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "1804f75786482946258ff0e827274357c49e90a7f2f568add7353249f2ab78b9", + "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3cb7e02c61d4a21d8289289b874b25e8b020c1d553e5af950160bffc14f51c18", + "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "2ad4b1311a0e39c359798375912faa91b4e13cd473bd59efd1e4f721777d254f", + "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "ab19efb741a127615b9022dedf1d895b53c69740cc3da745f9b9888bade9d98b", + "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "492cc11d54df410c2547890803930fc65950e6b81ced512e24bef56c3e70f3d2", + "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "c5a631a41f417336f3f65c85adefd1fb0bacc02465485f37d29fc1223c9f6cec", + "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "0701183b615d9eec9daea724d4cd8fa98dede2260cfb6b137d6cbf8ad6b29a4f", + "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "cb70e92d5275862b500614d79eaea3d19319b96798f4850cb19dea9a8038a651", + "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "908cbe562d82cca1bf176fdc99af867966ea423d244c4a50e14bad19f6878201", + "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "8580a3eb6d6df1774f4b6ca06dc1195c42b1e2a463488a5d851e99b0ca6d0249", + "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "2627948036e905f2e280663c56c86c172e2b0d057311ade7ca238953b7e0c36a", + "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "526e4f129fdb4b2c8f4317c57105a09ff03e71771d6d6bbbc9380917b5440d71", + "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "fd9dcf60838376478d7cc505ec7fc39f86f9d042646a3b836e9c06825927c7eb", + "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "664c1255a9435d1ad086329a3c215974b9302d481762240cc9d0328d9f1b8c9a", + "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "a585ce7684e4174f03adb09df17221e1729e8179dbc91b9a0f8813c3ecc0822d", + "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.gz": "59a1d91009b506a5bce3c276993cb8acfd71f73d01f9eaf4195b36114ac822c3", + "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.xz": "f86f3309cf2784b076f14e7da9e921c294a7701ea92d378c609061deccbc6bff", + "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f5c074461409b33a9791325d4014e6861ad36f99b9e48e54ecceb73986450be1", + "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "045431eec6f839b1c40b5a75c5000f80bd6351274a59b29d962833495324ecb6", + "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a3abfb68e60544170f47209bbf048f1374e5bb75901a529e2ac2f315758155f8", + "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "398c41a3219781c7cf1a907406506526b672abca6d3ab59c30556390a5f992c9", + "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "38895e615efd0bf75ca14b0ab0a085527cca64fae17631d1780a8f51acd26d17", + "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "786f40030dbe5e6897aafe4bda44770920b2010b93fc5ce86574774e531e2eff", + "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "7003cab7650dae7e3d29032422a57782a2c146024c437a6466ae1dd2b61a6618", + "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "bed3cc10203e8bd4d43b6245928c8a607acc5b6e633635caea45eb4eef4bda56", + "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "84cdea91c9f1e848ea17f554229ca80d18d093fc609641d8f003c4f2d4871866", + "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "a20fce7512f7c8cc6230a0f63f12855b04370d25e621183f71aa444c90c36b4b", + "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "87e0c484ade99efab57c655ef96dbabf7a02314540575b65a14372ab5496c36c", + "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "469757d8f35c9f4210aefd2ba660ee249e4409d47b908a6c68c1e650ee81ae67", + "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "4a38000480fe78fd5da7f9b71d36f296a6ae103254d932c4de6b902354e86bbf", + "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "45945d6af237fe4c91fde7db02ca19e99bac56a911b8db79be9b6ab8bb3934e1", + "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.gz": "0b07375a9a6507fd4932a05b5aaf28ed349fe2040103f1cb69c8a2494437258f", + "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz": "143bd7ed3ca7b913ddd0cea7cda8d1a0e4c29cc2ccbb7d29f0e45c2a87c3ec46", + "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "9404c111b91fd092367b88adbc37dce10a98c443bd8d9e13a860e1fb4e3af96e", + "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "f9f432907c276edcae5ad8ade0264f3c03109be02e791a814edc8ad3d229637a", + "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "33425c90427424f0b30fa2a6331a3b59c680f1c1bd0d8845d7e6bc1e2f80292d", + "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "03792890c64c72f30143849894b15f0eb3d6ad735fceede9092abd900ee733e4", + "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "cf6f2bffa0db1b4b9b8e95801bf415dcce413f902e26f4c1831dff1a00752b99", + "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "9192fdb668df8d4cab776623db7d01e35af42fea94098c1d4ba53190825d81a8", + "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "a174e7e08da2abc6b84499360670188f5cc61b6d055967e04bf602ff3d831f45", + "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "5a59811027586863852b15fc2b603e7e69b19841f4c10d2527ef1fc5b77d8af2", + "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "645bb5dd7a96bb9292b9956cb9705e9aed2408e47728f245564f1f7404ede783", + "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1fe34911b082c3a5ca4f24656675c095d2cf56f8005be9ca2517d0ef7d0a2b37", + "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "f2d6403d81bb0afe2e14956828987a0bb044c95f2d9566e1d792dd922dad7914", + "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "d93fdafcbbfd50c88c3f4feb4c68b053882ccae02c45e1615aeeae5a86f4aa98", + "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.gz": "a9e997b03559b3dfa2a0eba6ed7a142d7651ea7f4ba4e788d9de807b50558e58", + "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.xz": "4412b5fbfab8c5b31e57cf8c4ce9a9d13cfc9c0a8174ea1fc8a7c05281e1cb54", + "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.gz": "1725c41500dbf6bea554f3d4acaba70167f0e89087aaa3eb3c0f8a99047c55c4", + "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.xz": "27db022494afebbe05605f134191e8b2e78bfdeaa638d4215174038ca9dd2fd7", + "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "dc1a05d49b773dba06808c1c50653ecac506b3433f0f6dfa307109a7c621cc1a", + "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "cc58ce3af8f5481ada4dc129079cd558664717526b2f7f9a02bde6bafb6f45ad", + "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "34cfe803126ae9218b17adfe833a55c697dfa50729ac83b642529f3682d12d15", + "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "c752dc8962656c09047151fd24166f3134fbeed85006b5d22496691079c7fb9c", + "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "386b086b8aad922050c813dd58bb79a52ef806b2d1413e2e9cc46d6e43b81d7c", + "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "d9eec9ab7c265444ac5f04d4ec9e77d4c0c3c2e34c5804db8abf5f94c8fd2272", + "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "91df129046443554bfb836d25886aa9807b917acbc9dcf30f6531cde7bf912fa", + "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "ca9b574b9f2e914b5a6d9e011aba805d1e6f9b687dc1a1868e88f0e4d9e4401c", + "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "8b44f96a1ccd6d501b0af3960edb2c1a6c93957676a1c2cdb831e614de398f8b", + "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "f8a10a6767b80bf24f73223b9e46e1b18b6bf6746ad2115eb8968a0e482f0e4e", + "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a197208807503a9cfbc6df938d614a192da48884b2e4892f7b1d234579091be1", + "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "af3a1a33942bd8a3417593dc118abb1db0373f5410f54771713c05bb86724fed", + "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "5a3a3aa73b6a0f21c63b9a40bdbd0bb4dc59bd75add0a06e292ced791fad31be", + "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "6d7903f1c9fc95a23448717326d667dce59e54aaff821443d3cd9137cf3537fb", + "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.gz": "64eede54da4bf88b0a42ecf7f7a4bf8002b5550e60a64e1e48244c7f5b04768c", + "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz": "0a8f95e3bb0bebf9bcc8116b91bab3ba97cb6ff4021713586280aaceed9da030", + "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "58f9e0dd9c1aadde2dfd869528adadd4acc29ab0850236f3cee5f023d4211939", + "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "a211a962093e0d09358d51a6eb48da0966a02383c6b00c8acc077b5663d7d707", + "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "5631926874dc54204c319137a77a89de5e6f408de2a832109e2be71ea79f27d1", + "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a8cf87bc663b5e3dbcc97b0eb58bb1b9b5b0100aacb47dc0c372fe1612517244", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "1011f98197a9fe82d6095f4521934a06eea5f7e9719a6e4c9e3bf13d68f799ca", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "79599b3f91f9372262e97a417f4e104ef5192c0f6f8df204aea9c8b3ee39430e", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.gz": "7179a453bdcb17e401c0af8f4ab86cb5a4752a8ec80b0cbdd4cf1854c7f36a35", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.xz": "d565fc366fdbc305fbfe59e72b971c58f201d69e03a9ffa667d2ca0735cdb7f3", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "ae6bd8e20560d48519290d78e3d21f84b983403ca1f8f466a85496276d7866da", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "c7c0f8f44b0275456a27952178caa04c32eb9a1507056ddc05926a0730e17359", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "3246797ddbc9118de819b13b005b83748338f3c825a7436ebd5aa79ca55539c0", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "c7e784e77dbabedad88d24d2ae6dc4abb68bc04b1cd6c9d45f6dc28b6d0e2edc", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "c9452de4b3f15f0cf0b7d737b217b2cc7b88a96543bd8ce587ee14be1e21a90a", + "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "de9b05278a5c69d53ccbb31223526ea2aa2275c0fb3f046d1c1b4d67c0b0c275", + "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3734353a58dbf6c3831cc6b4ea606357140c191c89e8dfca1d7aa2f3fb8ac53d", + "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "e5e3a6e609fbfd537aa4acfefd3681d4b6c8029e2801a1ef23e8b09cf5a47bfe", + "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "22f54857e01d759301d099b67547cdc485596499088d0d749d38058c28e0f752", + "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "db48a9d45dc7c7aad4c9bb0d20789dd35fb6ef7a966948c44fbbae132de4c16b", + "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "fa5d1fb9f3627e7d59269a1f8008d780c685ea04975473f1808287134e7bc5a7", + "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "61ab625b47fa9097af90a79a1e75a2f2492a415f4009c9043cf453bd4128f031", + "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cc79969341fc60991059d0e3f13a69489c1e0915ea5787a88b8605ed5b7f3cd0", + "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "bbdb75f922b4b1716b033d91c76c4c0aa53061d6e7fa53a9bf16fe076814bbb2", + "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "13ca68afc3f3970a37951504664b58035102e1ae06d10a744389603b2f7499f5", + "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "04b174aa724945b6359a555892506c6a742a7c427464e8206433bb3f9a65fc02", + "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "430333380a590a9de211c8d735989fedb89321cf9f5f9a0b1ef651ec8b598691", + "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "924713e648806945cd56e54d4c11dc74b65241c8dbf6cc7b401c5c93d0f7ffdb", + "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "bb6e5a8b5cc88099e613aa5f4d926165976d8e4a7fccbecf4ac3b0eb966d7a0f", + "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "34d5e970304e1734aacb26c095e926c27a07e1a41fe70db9fa2997bef97ad3ec", + "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "835447a1d9d60659e99903275f327641809fc0148f35149f980d1a17ff87cc9a", + "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "ddd84a7f900aa239f93711f7da71e57aaedeeba2c9c8a8f23608acc7e48613c0", + "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "02f0af2bdae167c6091099a9b54ceb150c22b0f20dc861587a02cac78deb0b39", + "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "822f78f39dcbe3282bf7888a8cdae04efe7b023ded026a7e7f430e4ff15e7942", + "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "68a6189652c11a2c142c5339e2f5fb09d5f3e85d860bff063f62d5d3a3d111bf", + "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "6740ea882effa2fb87dd72744c08888ce5ec59c9797c00369156b24847bb180e", + "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "0bb365e2d895ef3c39c4899a01187a23f9b7c5195c30bf845da3917f62f5eafd", + "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "2e54c9887bc6ed1eb09b9f69c8425da843ea12bf33248fa0ccdc0d14387c1c57", + "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b0c0fe437921d17e2f50cbff87beeac067efa3d5211a241fb6f4c10b8ab500ac", + "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "64e7282c0cf4a714b11eed1d28be3a64ba0ccc6d899211a872a5a7809d514c08", + "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "100cfde057c81460b8cfde2047fe83ddde360a6df1ff178da5a968b17ecc9df8", + "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "38e8712e98fa0bc6962ab2fd2e3b96a2a5dcaa6c16161d8caf71131a1ca5031e", + "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "4dab52b50e19348fb39fdad39ab44189c27c10f80b5fbe2cc4723b644611fa87", + "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "36d1b2c9150fafc5976c296200ba3fac3e923df3e6f18032068200e2a887146c", + "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "7cb4a536320c23d305ce3bd3b7a954d951bf4d358ef3732be75b9b290c4818a5", + "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "ede1afc7dc5892ef6f780e987737e145c4b4d00495da8c2e9902182a3a174e20", + "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "e2d2d561cbfa0add0e5349682976216d3a7cff4094372c1ed26854bb4e4d93fd", + "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "e0380e65e83e4131f6aa7ee4e185689add4372b0c1653312e2ffd56072fdd0fe", + "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "73a140c7ed9c80f209ff976c63b0a34d625d651553c38692c91f048f4e0ae470", + "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9946b7120465181e05916b8023bc075b32bd85cf45a3b1d8bfba2f94ac78d927", + "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "eda273f27714b1e45adcc2388149f48de0e32a9104db0b9d1a02f6d37de43fef", + "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "f2955a4b696d050c219a96c093162b42a2fab921f9f3cb7570f8462928306c6d", + "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "ec900cc2d3c6d45ef039653f4418f9b9a4a5fddd5d7e8077c3fb08b36c539a28", + "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "04e6999a3405acc79f5fdcafeeab52880e5eeeedd3909b5f3c57e7647c86ef99", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "0730c5ebd576fec5371085f9fac0adde9424e1d7626456ed33bc66351b0ad307", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "90cbd84b8d48f0235a1954166f5edd53dc3031532ec6dfcb364f9a9624c9ce11", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "5f5c62d321db27eb495f6ea312ef8bea0bf17a7a501a44e062986c416951700f", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "a3bf64e2f22436e4484fc818f69d2f750fddd05a96463fd4abfcf655edce36b9", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a847a6f9c7a3ce71c7cd8d81bdfcfcd8e4d128aa28ba0dafea89b0cc37c6c36c", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "21fa794456566c64d08f629a385f89b3cfe9d9b69f317ae85fbe7425419108ff", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "b3f792f10a98993b4b55d1df951727a4422102d51b1145e51824268d48587ad0", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d791f0ec3c004e7baa0381962bf8ca2f18a3c861152702de5301d0149260e7fa", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "9807b2887e976d29f0c04484f8459175b4f6b70ef000037cdc4dada48e3cbd74", + "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "019920d64778af62879e2146c2c13d9f6e2165a38bbfa1982694bfb48864d308" } } diff --git a/src/tools/cargo b/src/tools/cargo index 80d5b607dde6e..6087566b3fa73 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 80d5b607dde6ef97dfff4e23923822c01d2bb036 +Subproject commit 6087566b3fa73bfda29702632493e938b12d19e5 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index bd3a04e34ae31..9c9ea11408143 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,62 @@ document. ## Unreleased / Beta / In Rust Nightly -[66c29b97...master](https://github.com/rust-lang/rust-clippy/compare/66c29b97...master) +[93f0a9a9...master](https://github.com/rust-lang/rust-clippy/compare/93f0a9a9...master) + +## Rust 1.78 + +Current stable, released 2024-05-02 + +[View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster) + +### New Lints + +* [`assigning_clones`] + [#12077](https://github.com/rust-lang/rust-clippy/pull/12077) +* [`mixed_attributes_style`] + [#12354](https://github.com/rust-lang/rust-clippy/pull/12354) +* [`empty_docs`] + [#12342](https://github.com/rust-lang/rust-clippy/pull/12342) +* [`unnecessary_get_then_check`] + [#12339](https://github.com/rust-lang/rust-clippy/pull/12339) +* [`multiple_bound_locations`] + [#12259](https://github.com/rust-lang/rust-clippy/pull/12259) +* [`unnecessary_clippy_cfg`] + [#12303](https://github.com/rust-lang/rust-clippy/pull/12303) +* [`deprecated_clippy_cfg_attr`] + [#12292](https://github.com/rust-lang/rust-clippy/pull/12292) +* [`manual_c_str_literals`] + [#11919](https://github.com/rust-lang/rust-clippy/pull/11919) +* [`ref_as_ptr`] + [#12087](https://github.com/rust-lang/rust-clippy/pull/12087) +* [`lint_groups_priority`] + [#11832](https://github.com/rust-lang/rust-clippy/pull/11832) +* [`unnecessary_result_map_or_else`] + [#12169](https://github.com/rust-lang/rust-clippy/pull/12169) +* [`to_string_trait_impl`] + [#12122](https://github.com/rust-lang/rust-clippy/pull/12122) +* [`incompatible_msrv`] + [#12160](https://github.com/rust-lang/rust-clippy/pull/12160) + +### Enhancements + +* [`thread_local_initializer_can_be_made_const`]: Now checks the [`msrv`] configuration + [#12405](https://github.com/rust-lang/rust-clippy/pull/12405) +* [`disallowed_macros`]: Code generated by derive macros can no longer allow this lint + [#12267](https://github.com/rust-lang/rust-clippy/pull/12267) +* [`wildcard_imports`]: Add configuration [`allowed-wildcard-imports`] to allow preconfigured wildcards + [#11979](https://github.com/rust-lang/rust-clippy/pull/11979) + +### ICE Fixes + +* [`ptr_as_ptr`]: No longer ICEs when the cast source is a function call to a local variable + [#12617](https://github.com/rust-lang/rust-clippy/pull/12617) +* [`cast_sign_loss`]: Avoids an infinite loop when casting two chained `.unwrap()` calls + [#12508](https://github.com/rust-lang/rust-clippy/pull/12508) ## Rust 1.77 -Current stable, released 2024-03-18 +Released 2024-03-18 [View all 93 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-12-16T18%3A20%3A00Z..2024-01-25T18%3A15%3A56Z+base%3Amaster) @@ -5891,6 +5942,7 @@ Released 2018-09-13 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 43f20ecedc21d..b48f3ab3919cc 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.79" +version = "0.1.80" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -30,7 +30,7 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] -ui_test = "0.22.2" +ui_test = "0.23" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index b80ac6370e7a5..415022612caaa 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -299,10 +299,10 @@ This is good, because it makes writing this particular lint less complicated. We have to make this decision with every new Clippy lint. It boils down to using either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. -In short, the `LateLintPass` has access to type information while the -`EarlyLintPass` doesn't. If you don't need access to type information, use the -`EarlyLintPass`. The `EarlyLintPass` is also faster. However, linting speed -hasn't really been a concern with Clippy so far. +In short, the `EarlyLintPass` runs before type checking and +[HIR](https://rustc-dev-guide.rust-lang.org/hir.html) lowering and the `LateLintPass` +has access to type information. Consider using the `LateLintPass` unless you need +something specific from the `EarlyLintPass`. Since we don't need type information for checking the function name, we used `--pass=early` when running the new lint automation and all the imports were diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 7cefa6852642b..f6af9810ca166 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -132,6 +132,16 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` * [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +## `allow-useless-vec-in-tests` +Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) + + ## `allowed-dotfiles` Additional dotfiles (files or directories starting with a dot) to allow @@ -506,13 +516,14 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large ## `ignore-interior-mutability` -A list of paths to types that should be treated like `Arc`, i.e. ignored but -for the generic parameters for determining interior mutability +A list of paths to types that should be treated as if they do not contain interior mutability **Default Value:** `["bytes::Bytes"]` --- **Affected lints:** +* [`borrow_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const) +* [`declare_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const) * [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) * [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index 8ba2ab5662569..7f7dc9d6cfb0e 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.79" +version = "0.1.80" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 781282213cc4a..5cfcbdb57d735 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -463,14 +463,17 @@ define_Conf! { /// /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` (allow_print_in_tests: bool = false), + /// Lint: USELESS_VEC. + /// + /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + (allow_useless_vec_in_tests: bool = false), /// Lint: RESULT_LARGE_ERR. /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. /// - /// A list of paths to types that should be treated like `Arc`, i.e. ignored but - /// for the generic parameters for determining interior mutability + /// A list of paths to types that should be treated as if they do not contain interior mutability (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), /// Lint: UNINLINED_FORMAT_ARGS. /// diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index 59dd5b334b84b..14808440d48d3 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -23,7 +23,7 @@ msrv_aliases! { 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } - 1,63,0 { ASSIGNING_CLONES } + 1,63,0 { CLONE_INTO } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 1d954607eee8c..5e3a119337ccd 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.79" +version = "0.1.80" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index dc7f44af2b74b..f0dafb1ae0d52 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// a.clone_from(&b); /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub ASSIGNING_CLONES, perf, "assigning the result of cloning may be inefficient" @@ -153,7 +153,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. // If the current MSRV is below that, don't suggest the lint. - if !msrv.meets(msrvs::ASSIGNING_CLONES) && matches!(call.target, TargetTrait::ToOwned) { + if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 4062212f408ef..8459f051d3d9a 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -121,9 +121,9 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(sig) = expr_sig(cx, path) && let Some(input) = sig.input(index) - && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() + && let Some(input_ty) = input.no_bound_vars() { - input.no_bound_vars().is_some() + input_ty == cx.typeck_results().expr_ty_adjusted(expr) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index ca7fa4e5a4109..593bc6c81ee8e 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -197,7 +197,7 @@ declare_clippy_lint! { /// pedantic = { level = "warn", priority = -1 } /// similar_names = "allow" /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub LINT_GROUPS_PRIORITY, correctness, "a lint group in `Cargo.toml` at the same priority as a lint" diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index dbfa8e1ee91b2..7c5acd1a678d7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -40,9 +40,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1)) }) }, - BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) + BinOpKind::Rem => get_constant_bits(cx, right) .unwrap_or(u64::MAX) .min(apply_reductions(cx, nbits, left, signed)), + BinOpKind::BitAnd => get_constant_bits(cx, right) + .unwrap_or(u64::MAX) + .min(get_constant_bits(cx, left).unwrap_or(u64::MAX)) + .min(apply_reductions(cx, nbits, right, signed)) + .min(apply_reductions(cx, nbits, left, signed)), BinOpKind::Shr => apply_reductions(cx, nbits, left, signed) .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())), _ => nbits, diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index d14898a8196cf..bd2c96f01f6f4 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -708,7 +708,7 @@ declare_clippy_lint! { /// let a_ref = &1; /// let a_ptr = std::ptr::from_ref(a_ref); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub REF_AS_PTR, pedantic, "using `as` to cast a reference to pointer" diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index 6942ca5364042..70856b808810b 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::{for_each_expr_with_closures, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; +use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -77,7 +77,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: || is_type_lang_item(cx, ty, LangItem::String) } -fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool { +fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool { let mut has_access = false; let mut has_read_access = false; @@ -109,11 +109,30 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc // traits (identified as local, based on the orphan rule), pessimistically assume that they might // have side effects, so consider them a read. if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id) - && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind + && let ExprKind::MethodCall(_, receiver, args, _) = parent.kind && path_to_local_id(receiver, id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && !method_def_id.is_local() { + // If this "official" method takes closures, + // it has read access if one of the closures has read access. + // + // items.retain(|item| send_item(item).is_ok()); + let is_read_in_closure_arg = args.iter().any(|arg| { + if let ExprKind::Closure(closure) = arg.kind + // To keep things simple, we only check the first param to see if its read. + && let Body { params: [param, ..], value } = cx.tcx.hir().body(closure.body) + { + !has_no_read_access(cx, param.hir_id, *value) + } else { + false + } + }); + if is_read_in_closure_arg { + has_read_access = true; + return ControlFlow::Break(()); + } + // The method call is a statement, so the return value is not used. That's not a read access: // // id.foo(args); diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index acdcb54be2719..ccf1d9d6f8c0d 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; -use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop}; +use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, - if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, + is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -159,40 +158,36 @@ declare_clippy_lint! { "`if` statement with shared code in all blocks" } -pub struct CopyAndPaste { +pub struct CopyAndPaste<'tcx> { ignore_interior_mutability: Vec, - ignored_ty_ids: DefIdSet, + interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste { +impl CopyAndPaste<'_> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignored_ty_ids: DefIdSet::new(), + interior_mut: InteriorMut::default(), } } } -impl_lint_pass!(CopyAndPaste => [ +impl_lint_pass!(CopyAndPaste<'_> => [ IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, BRANCHES_SHARING_CODE ]); -impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { +impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for ignored_ty in &self.ignore_interior_mutability { - let path: Vec<&str> = ignored_ty.split("::").collect(); - for id in def_path_def_ids(cx, path.as_slice()) { - self.ignored_ty_ids.insert(id); - } - } + self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); - lint_same_cond(cx, &conds, &self.ignored_ty_ids); + lint_same_cond(cx, &conds, &mut self.interior_mut); lint_same_fns_in_if_cond(cx, &conds); let all_same = !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks); @@ -570,13 +565,14 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo }) } -fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool { +fn method_caller_is_mutable<'tcx>( + cx: &LateContext<'tcx>, + caller_expr: &Expr<'_>, + interior_mut: &mut InteriorMut<'tcx>, +) -> bool { let caller_ty = cx.typeck_results().expr_ty(caller_expr); - // Check if given type has inner mutability and was not set to ignored by the configuration - let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) - && !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did())); - is_inner_mut_ty + interior_mut.is_interior_mut_ty(cx, caller_ty) || caller_ty.is_mutable_ptr() // `find_binding_init` will return the binding iff its not mutable || path_to_local(caller_expr) @@ -585,7 +581,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore } /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) { +fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) { for (i, j) in search_same( conds, |e| hash_expr(cx, e), @@ -593,7 +589,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De // Ignore eq_expr side effects iff one of the expression kind is a method call // and the caller is not a mutable, including inner mutable type. if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { - if method_caller_is_mutable(cx, caller, ignored_ty_ids) { + if method_caller_is_mutable(cx, caller, interior_mut) { false } else { SpanlessEq::new(cx).eq_expr(lhs, rhs) diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index e229676743195..db5937266047d 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, Node}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro { !in_external_macro(cx.sess(), macro_call.span) && self.checked_dbg_call_site.insert(macro_call.span) && // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml - !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id)) + !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id)) { let mut applicability = Applicability::MachineApplicable; @@ -129,10 +129,6 @@ impl LateLintPass<'_> for DbgMacro { } } -fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool { - is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id) -} - fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 89e2b34496806..b936b28470b53 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -9,8 +9,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, - Pat, PatKind, Path, QPath, TyKind, UnOp, + self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, + PatKind, Path, QPath, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 80db617c639a5..003a9995c15f3 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, + is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -271,9 +271,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = root_macro_call(arg_span) - && self.cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - { + if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) { diag.span_suggestion( self.cx.sess().source_map().span_until_char(mac_call.span, '!'), message, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index d0c66900c0068..e7ec2b3151e6a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -185,7 +185,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) if let hir::PatKind::Wild = pat.kind { return false; // ignore `_` patterns } - if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) { + if cx.tcx.has_typeck_results(pat.hir_id.owner.def_id) { is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), tys) } else { false @@ -233,7 +233,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { - if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.def_id) && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys) && is_mutated_static(arg) { @@ -246,7 +246,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo MethodCall(_, receiver, args, _) => { let mut tys = DefIdSet::default(); for arg in std::iter::once(receiver).chain(args.iter()) { - if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.def_id) && is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys) && is_mutated_static(arg) { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 7b97fc15caaf8..3bf8d61895585 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// /// ### Limitations /// This lint does not check for implied bounds transitively. Meaning that - /// it does't check for implied bounds from supertraits of supertraits + /// it doesn't check for implied bounds from supertraits of supertraits /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index a4c3b06046e86..128461ce7bcf3 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -93,12 +93,9 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap = FxIndexMap::default(); pat.walk_always(|pat| { // We'll just ignore mut and ref mut for simplicity sake right now - if let hir::PatKind::Binding( - hir::BindingMode(by_ref, hir::Mutability::Not), - value_hir_id, - ident, - sub_pat, - ) = pat.kind && by_ref != hir::ByRef::Yes(hir::Mutability::Mut) + if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) = + pat.kind + && by_ref != hir::ByRef::Yes(hir::Mutability::Mut) { // This block catches bindings with sub patterns. It would be hard to build a correct suggestion // for them and it's likely that the user knows what they are doing in such a case. diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index afcb674594767..208d1bb6e68a1 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -1,10 +1,13 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; +use clippy_utils::macros::macro_backtrace; use clippy_utils::source::snippet; -use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; +use rustc_hir::{ArrayLen, Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -25,20 +28,41 @@ declare_clippy_lint! { pub struct LargeStackArrays { maximum_allowed_size: u128, + prev_vec_macro_callsite: Option, } impl LargeStackArrays { #[must_use] pub fn new(maximum_allowed_size: u128) -> Self { - Self { maximum_allowed_size } + Self { + maximum_allowed_size, + prev_vec_macro_callsite: None, + } + } + + /// Check if the given span of an expr is already in a `vec!` call. + fn is_from_vec_macro(&mut self, cx: &LateContext<'_>, span: Span) -> bool { + // First, we check if this is span is within the last encountered `vec!` macro's root callsite. + self.prev_vec_macro_callsite + .is_some_and(|vec_mac| vec_mac.contains(span)) + || { + // Then, we try backtracking the macro expansions, to see if there's a `vec!` macro, + // and update the `prev_vec_macro_callsite`. + let res = macro_backtrace(span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id)); + if res { + self.prev_vec_macro_callsite = Some(span.source_callsite()); + } + res + } } } impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind + && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) @@ -54,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( + span_lint_and_then( cx, LARGE_STACK_ARRAYS, expr.span, @@ -62,12 +86,33 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { "allocating a local array larger than {} bytes", self.maximum_allowed_size ), - None, - format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), + |diag| { + if !might_be_expanded(cx, expr) { + diag.help(format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + )); + } + }, ); } } } + +/// Only giving help messages if the expr does not contains macro expanded codes. +fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { + /// Check if the span of `ArrayLen` of a repeat expression is within the expr's span, + /// if not, meaning this repeat expr is definitely from some proc-macro. + /// + /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the + /// correct result. + fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { + let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else { + return false; + }; + let len_span = cx.tcx.def_span(anon_const.def_id); + !expr.span.contains(len_span) + } + + expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr) +} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index e2aac58bf9793..2c44c3881aa77 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -535,6 +535,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_print_in_tests, allow_private_module_inception, allow_unwrap_in_tests, + allow_useless_vec_in_tests, ref allowed_dotfiles, ref allowed_idents_below_min_chars, ref allowed_scripts, @@ -754,6 +755,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { too_large_for_stack, msrv: msrv(), span_to_lint_map: BTreeMap::new(), + allow_in_test: allow_useless_vec_in_tests, }) }); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs index 31f0f1cfeba31..40ccfec02be58 100644 --- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,11 +1,12 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, pat_is_wild, sugg}; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_span::sym; /// Checks for the `UNUSED_ENUMERATE_INDEX` lint. /// @@ -16,9 +17,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_ && let ty = cx.typeck_results().expr_ty(arg) && pat_is_wild(cx, &index.kind, body) && let ty::Adt(base, _) = *ty.kind() - && match_def_path(cx, base.did(), &clippy_utils::paths::CORE_ITER_ENUMERATE_STRUCT) + && cx.tcx.is_diagnostic_item(sym::Enumerate, base.did()) && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) - && match_def_path(cx, call_id, &clippy_utils::paths::CORE_ITER_ENUMERATE_METHOD) + && cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 76edbe8b755bd..d76b94eba23ed 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -1,12 +1,11 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { && !expr.span.from_expansion() && let then = peel_blocks_with_stmt(then) && let Some(macro_call) = root_macro_call(then.span) - && cx.tcx.item_name(macro_call.def_id) == sym::panic + && is_panic(cx, macro_call.def_id) && !cx.tcx.sess.source_map().is_multiline(cond.span) && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span) && let Some(panic_snippet) = panic_snippet.strip_suffix(')') diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 338a299740a87..6f6ba1852a681 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -1,15 +1,15 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::root_macro_call; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; -use clippy_utils::{higher, in_constant}; +use clippy_utils::{higher, in_constant, path_to_local, peel_ref_operators}; use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; +use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -97,12 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { return; } - if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) - { + if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); - check_is_ascii(cx, macro_call.span, recv, &range); + check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym!(contains) @@ -111,42 +109,67 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { end: Some(end), limits: RangeLimits::Closed, }) = higher::Range::hir(receiver) + && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_)) { + let arg = peel_ref_operators(cx, arg); + let ty_sugg = get_ty_sugg(cx, arg, start); let range = check_range(start, end); - if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { - check_is_ascii(cx, expr.span, e, &range); - } else { - check_is_ascii(cx, expr.span, arg, &range); - } + check_is_ascii(cx, expr.span, arg, &range, ty_sugg); } } extract_msrv_attr!(LateContext); } -fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) { - if let Some(sugg) = match range { - CharRange::UpperChar => Some("is_ascii_uppercase"), - CharRange::LowerChar => Some("is_ascii_lowercase"), - CharRange::FullChar => Some("is_ascii_alphabetic"), - CharRange::Digit => Some("is_ascii_digit"), - CharRange::HexDigit => Some("is_ascii_hexdigit"), - CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None, - } { - let default_snip = ".."; - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); +fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> { + if let ExprKind::Lit(lit) = bound_expr.kind + && let local_hid = path_to_local(arg)? + && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) + // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given + && ty_span == span + { + let ty_str = match lit.node { + Char(_) => "char", + Byte(_) => "u8", + _ => return None, + }; + return Some((*ty_span, ty_str)); + } + None +} - span_lint_and_sugg( - cx, - MANUAL_IS_ASCII_CHECK, - span, - "manual check for common ascii range", - "try", - format!("{recv}.{sugg}()"), - app, - ); +fn check_is_ascii( + cx: &LateContext<'_>, + span: Span, + recv: &Expr<'_>, + range: &CharRange, + ty_sugg: Option<(Span, &'_ str)>, +) { + let sugg = match range { + CharRange::UpperChar => "is_ascii_uppercase", + CharRange::LowerChar => "is_ascii_lowercase", + CharRange::FullChar => "is_ascii_alphabetic", + CharRange::Digit => "is_ascii_digit", + CharRange::HexDigit => "is_ascii_hexdigit", + CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => return, + }; + let default_snip = ".."; + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); + let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))]; + if let Some((ty_span, ty_str)) = ty_sugg { + suggestion.push((ty_span, format!("{recv}: {ty_str}"))); } + + span_lint_and_then( + cx, + MANUAL_IS_ASCII_CHECK, + span, + "manual check for common ascii range", + |diag| { + diag.multipart_suggestion("try", suggestion, app); + }, + ); } fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { @@ -187,11 +210,3 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { CharRange::Otherwise } } - -fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { - if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) { - return sym::matches_macro == name; - } - - false -} diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 6746920edc516..90cfdecc19936 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -1,3 +1,4 @@ +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet; @@ -11,12 +12,12 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; -use super::COLLAPSIBLE_MATCH; +use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH}; -pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { +pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { - check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body)); + check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv); } } } @@ -26,8 +27,9 @@ pub(super) fn check_if_let<'tcx>( pat: &'tcx Pat<'_>, body: &'tcx Expr<'_>, else_expr: Option<&'tcx Expr<'_>>, + msrv: &Msrv, ) { - check_arm(cx, false, pat, body, None, else_expr); + check_arm(cx, false, pat, body, None, else_expr, msrv); } fn check_arm<'tcx>( @@ -37,6 +39,7 @@ fn check_arm<'tcx>( outer_then_body: &'tcx Expr<'tcx>, outer_guard: Option<&'tcx Expr<'tcx>>, outer_else_body: Option<&'tcx Expr<'tcx>>, + msrv: &Msrv, ) { let inner_expr = peel_blocks_with_stmt(outer_then_body); if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr) @@ -57,7 +60,7 @@ fn check_arm<'tcx>( // match expression must be a local binding // match { .. } && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)) - && !pat_contains_or(inner_then_pat) + && !pat_contains_disallowed_or(inner_then_pat, msrv) // the binding must come from the pattern of the containing match arm // .... => match { .. } && let (Some(binding_span), is_innermost_parent_pat_struct) @@ -142,13 +145,3 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi }); (span, is_innermost_parent_pat_struct) } - -fn pat_contains_or(pat: &Pat<'_>) -> bool { - let mut result = false; - pat.walk(|p| { - let is_or = matches!(p.kind, PatKind::Or(_)); - result |= is_or; - !is_or - }); - result -} diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index fae2c4e4af92e..ee9f48d71ad80 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -27,7 +27,7 @@ mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg}; -use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat}; +use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -1040,7 +1040,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); } - collapsible_match::check_match(cx, arms); + collapsible_match::check_match(cx, arms, &self.msrv); if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); @@ -1066,7 +1066,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { needless_match::check_match(cx, ex, arms, expr); match_on_vec_items::check(cx, ex); match_str_case_mismatch::check(cx, ex, arms); - redundant_guards::check(cx, arms); + redundant_guards::check(cx, arms, &self.msrv); if !in_constant(cx, expr.hir_id) { manual_unwrap_or::check(cx, expr, ex, arms); @@ -1083,7 +1083,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { - collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else); + collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); if !from_expansion { if let Some(else_expr) = if_let.if_else { if self.msrv.meets(msrvs::MATCHES_MACRO) { @@ -1195,3 +1195,18 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar Err(()) => true, } } + +/// Checks if `pat` contains OR patterns that cannot be nested due to a too low MSRV. +fn pat_contains_disallowed_or(pat: &Pat<'_>, msrv: &Msrv) -> bool { + if msrv.meets(msrvs::OR_PATTERNS) { + return false; + } + + let mut result = false; + pat.walk(|p| { + let is_or = matches!(p.kind, PatKind::Or(_)); + result |= is_or; + !is_or + }); + result +} diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 50cbccc396839..a75cf37945f77 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -1,40 +1,32 @@ +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr, is_local_used}; use clippy_utils::{in_constant, path_to_local}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, Pat, PatKind, UnOp}; +use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; use std::borrow::Cow; use std::ops::ControlFlow; -use super::REDUNDANT_GUARDS; +use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS}; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { for outer_arm in arms { let Some(guard) = outer_arm.guard else { continue; }; // `Some(x) if matches!(x, y)` - if let ExprKind::Match( - scrutinee, - [ - arm, - Arm { - pat: Pat { - kind: PatKind::Wild, .. - }, - .. - }, - ], - MatchSource::Normal, - ) = guard.kind + if let ExprKind::Match(scrutinee, [arm, _], MatchSource::Normal) = guard.kind + && matching_root_macro_call(cx, guard.span, sym::matches_macro).is_some() && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm) + && !pat_contains_disallowed_or(arm.pat, msrv) { let pat_span = match (arm.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, @@ -53,6 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { // `Some(x) if let Some(2) = x` else if let ExprKind::Let(let_expr) = guard.kind && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm) + && !pat_contains_disallowed_or(let_expr.pat, msrv) { let pat_span = match (let_expr.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 37f72528140f1..69791414f72c6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -75,7 +75,7 @@ fn report_single_pattern( ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; let ctxt = expr.span.ctxt(); - let mut app = Applicability::HasPlaceholders; + let mut app = Applicability::MachineApplicable; let els_str = els.map_or(String::new(), |els| { format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 581e3b308c3cd..02a11257007a9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::macros::{is_panic, root_macro_call}; +use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; @@ -247,8 +247,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { } else { None } - } else if let Some(macro_call) = root_macro_call(expr.span) - && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro) + } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some() // we know for a fact that the wildcard pattern is the second arm && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind && path_to_local_id(scrutinee, filter_param_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index 6d70989546a25..03b4680c52242 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -89,8 +89,7 @@ pub(super) fn check<'tcx>( } match it.kind { - PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) - | PatKind::Ref(_, Mutability::Mut) => { + PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false }, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 0939c02856429..63545d6c50359 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1145,11 +1145,16 @@ declare_clippy_lint! { /// `str` as an argument, e.g., `_.split("x")`. /// /// ### Why is this bad? - /// Performing these methods using a `char` is faster than - /// using a `str`. + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. /// /// ### Known problems - /// Does not catch multi-byte unicode characters. + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. /// /// ### Example /// ```rust,ignore @@ -1162,7 +1167,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub SINGLE_CHAR_PATTERN, - perf, + pedantic, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } @@ -3988,7 +3993,7 @@ declare_clippy_lint! { /// let x: Result = Ok(0); /// let y = x.unwrap_or_else(|err| handle_error(err)); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub UNNECESSARY_RESULT_MAP_OR_ELSE, suspicious, "making no use of the \"map closure\" when calling `.map_or_else(|err| handle_error(err), |n| n)`" @@ -4022,7 +4027,7 @@ declare_clippy_lint! { /// needs_cstr(c"Hello"); /// unsafe { libc::puts(c"World".as_ptr()) } /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, pedantic, r#"creating a `CStr` through functions when `c""` literals can be used"# diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs index 9b0180d936991..774aaec1afda4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs +++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs @@ -4,7 +4,7 @@ use clippy_utils::mir::{enclosing_mir, visit_local_usage}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node}; +use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::mir::{Location, START_BLOCK}; use rustc_span::sym; @@ -25,6 +25,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && is_unwrap_call(cx, unwrap_call_expr) && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id) && let Node::LetStmt(local) = parent + && let PatKind::Binding(.., ident, _) = local.pat.kind + // if the binding is prefixed with `_`, it typically means + // that this guard only exists to protect a section of code + // rather than the contained data + && !ident.as_str().starts_with('_') && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) && let Some((local, _)) = mir .local_decls diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs index 44a7ad394fa0c..20ec2b74d81e4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs index 363b1f2b81229..982a7901c4537 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; -const PATTERN_METHODS: [(&str, usize); 24] = [ +const PATTERN_METHODS: [(&str, usize); 22] = [ ("contains", 0), ("starts_with", 0), ("ends_with", 0), @@ -27,8 +27,6 @@ const PATTERN_METHODS: [(&str, usize); 24] = [ ("rmatches", 0), ("match_indices", 0), ("rmatch_indices", 0), - ("strip_prefix", 0), - ("strip_suffix", 0), ("trim_start_matches", 0), ("trim_end_matches", 0), ("replace", 0), @@ -50,7 +48,7 @@ pub(super) fn check( && args.len() > pos && let arg = &args[pos] && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) + && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs index 0698bd6a0c523..97c13825bc104 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs index e5cc898612e9a..8b8a965b9f0c9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then}; -use clippy_utils::paths::{CORE_ITER_ENUMERATE_METHOD, CORE_ITER_ENUMERATE_STRUCT}; use clippy_utils::source::{snippet, snippet_opt}; -use clippy_utils::{expr_or_init, is_trait_method, match_def_path, pat_is_wild}; +use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; use rustc_lint::LateContext; @@ -42,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, let recv_ty = cx.typeck_results().expr_ty(recv); if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did) // If we call a method on a `std::iter::Enumerate` instance - && match_def_path(cx, recv_ty_defid, &CORE_ITER_ENUMERATE_STRUCT) + && cx.tcx.is_diagnostic_item(sym::Enumerate, recv_ty_defid) // If we are calling a method of the `Iterator` trait && is_trait_method(cx, call_expr, sym::Iterator) // And the map argument is a closure @@ -75,10 +74,10 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = recv_init_expr.kind && let Some(enumerate_defid) = cx.typeck_results().type_dependent_def_id(recv_init_expr.hir_id) // Make sure the method call is `std::iter::Iterator::enumerate`. - && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD) + && cx.tcx.is_diagnostic_item(sym::enumerate_method, enumerate_defid) { // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element - // that would be explicited in the closure. + // that would be explicitly in the closure. let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. // Fallback to `..` if we fail getting either snippet. diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index ef00c812d510a..c50f24f824ab0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -52,11 +52,17 @@ pub(super) fn get_hint_if_single_char_arg( cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability, + ascii_only: bool, ) -> Option { if let ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(r, style) = lit.node && let string = r.as_str() - && string.chars().count() == 1 + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 { let snip = snippet_with_applicability(cx, arg.span, string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index 191b32408efe1..d608f3bf7b4d5 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// F: Sized + std::fmt::Debug, /// {} /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, suspicious, "defining generic bounds in multiple locations" diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 8c2f43c97f4d9..2eb534da0925c 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_interior_mut_ty; -use clippy_utils::{def_path_def_ids, trait_ref_of_method}; -use rustc_data_structures::fx::FxHashSet; +use clippy_utils::trait_ref_of_method; +use clippy_utils::ty::InteriorMut; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; @@ -23,27 +22,15 @@ declare_clippy_lint! { /// ### Known problems /// /// #### False Positives - /// It's correct to use a struct that contains interior mutability as a key, when its + /// It's correct to use a struct that contains interior mutability as a key when its /// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types. /// However, this lint is unable to recognize this, so it will often cause false positives in - /// theses cases. The `bytes` crate is a great example of this. + /// these cases. /// /// #### False Negatives - /// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind - /// indirection. For example, `struct BadKey<'a>(&'a Cell)` will be seen as immutable - /// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`. - /// - /// This lint does check a few cases for indirection. Firstly, using some standard library - /// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and - /// `BTreeSet`) directly as keys (e.g. in `HashMap>, ()>`) **will** trigger the - /// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their - /// contained type. - /// - /// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`) - /// apply only to the **address** of the contained value. Therefore, interior mutability - /// behind raw pointers (e.g. in `HashSet<*mut Cell>`) can't impact the value of `Hash` - /// or `Ord`, and therefore will not trigger this link. For more info, see issue - /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). + /// This lint does not follow raw pointers (`*const T` or `*mut T`) as `Hash` and `Ord` + /// apply only to the **address** of the contained value. This can cause false negatives for + /// custom collections that use raw pointers internally. /// /// ### Example /// ```no_run @@ -51,13 +38,12 @@ declare_clippy_lint! { /// use std::collections::HashSet; /// use std::hash::{Hash, Hasher}; /// use std::sync::atomic::AtomicUsize; - ///# #[allow(unused)] /// /// struct Bad(AtomicUsize); /// impl PartialEq for Bad { /// fn eq(&self, rhs: &Self) -> bool { /// .. - /// ; unimplemented!(); + /// # ; true /// } /// } /// @@ -66,7 +52,7 @@ declare_clippy_lint! { /// impl Hash for Bad { /// fn hash(&self, h: &mut H) { /// .. - /// ; unimplemented!(); + /// # ; /// } /// } /// @@ -80,25 +66,16 @@ declare_clippy_lint! { "Check for mutable `Map`/`Set` key type" } -#[derive(Clone)] -pub struct MutableKeyType { +pub struct MutableKeyType<'tcx> { ignore_interior_mutability: Vec, - ignore_mut_def_ids: FxHashSet, + interior_mut: InteriorMut<'tcx>, } -impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]); +impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]); -impl<'tcx> LateLintPass<'tcx> for MutableKeyType { +impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - self.ignore_mut_def_ids.clear(); - let mut path = Vec::new(); - for ty in &self.ignore_interior_mutability { - path.extend(ty.split("::")); - for id in def_path_def_ids(cx, &path[..]) { - self.ignore_mut_def_ids.insert(id); - } - path.clear(); - } + self.interior_mut = InteriorMut::without_pointers(cx, &self.ignore_interior_mutability); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { @@ -121,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &hir::LetStmt<'tcx>) { if let hir::PatKind::Wild = local.pat.kind { return; } @@ -129,15 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } -impl MutableKeyType { +impl<'tcx> MutableKeyType<'tcx> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignore_mut_def_ids: FxHashSet::default(), + interior_mut: InteriorMut::default(), } } - fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + fn check_sig(&mut self, cx: &LateContext<'tcx>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'tcx>) { let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity(); for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { self.check_ty_(cx, hir_ty.span, *ty); @@ -151,7 +128,7 @@ impl MutableKeyType { // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased // generics (because the compiler cannot ensure immutability for unknown types). - fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { + fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); if let ty::Adt(def, args) = ty.kind() { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] @@ -162,11 +139,7 @@ impl MutableKeyType { } let subst_ty = args.type_at(0); - // Determines if a type contains interior mutability which would affect its implementation of - // [`Hash`] or [`Ord`]. - if is_interior_mut_ty(cx, subst_ty) - && !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) - { + if self.interior_mut.is_interior_mut_ty(cx, subst_ty) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 84a07df1bb0ac..630018238f4c4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -1,6 +1,6 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; +use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; @@ -35,6 +35,16 @@ declare_clippy_lint! { /// println!("{}", elem); /// } /// ``` + /// + /// ### Known Problems + /// When doing things such as: + /// ```ignore + /// let v = vec![0, 1, 2]; + /// v.iter().for_each(|elem| unsafe { + /// libc::printf(c"%d\n".as_ptr(), elem); + /// }); + /// ``` + /// This lint will not trigger. #[clippy::version = "1.53.0"] pub NEEDLESS_FOR_EACH, pedantic, @@ -68,7 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind && let body = cx.tcx.hir().body(body) - && let ExprKind::Block(..) = body.value.kind + // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` + // and suggesting `for … in … { unsafe { } }` is a little ugly. + && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind { let mut ret_collector = RetCollector::default(); ret_collector.visit_expr(body.value); diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 0c0b1a73351f5..6605d1fa51a36 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -6,8 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ - BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, - StmtKind, + BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 30d3e86dc4ed7..9e47c3ad0b7fb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -83,7 +83,9 @@ fn should_skip<'tcx>( } if is_self(arg) { - return true; + // Interestingly enough, `self` arguments make `is_from_proc_macro` return `true`, hence why + // we return early here. + return false; } if let PatKind::Binding(.., name, _) = arg.pat.kind { @@ -185,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } // Collect variables mutably used and spans which will need dereferencings from the // function body. - let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = { + let mutably_used_vars = { let mut ctx = MutablyUsedVariablesCtxt { mutably_used_vars: HirIdSet::default(), prev_bind: None, @@ -217,7 +219,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures); } } - ctx + ctx.generate_mutably_used_ids_from_aliases() }; for ((&input, &_), arg) in it { // Only take `&mut` arguments. @@ -309,12 +311,22 @@ struct MutablyUsedVariablesCtxt<'tcx> { } impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { - fn add_mutably_used_var(&mut self, mut used_id: HirId) { - while let Some(id) = self.aliases.get(&used_id) { + fn add_mutably_used_var(&mut self, used_id: HirId) { + self.mutably_used_vars.insert(used_id); + } + + // Because the alias may come after the mutable use of a variable, we need to fill the map at + // the end. + fn generate_mutably_used_ids_from_aliases(mut self) -> HirIdSet { + let all_ids = self.mutably_used_vars.iter().copied().collect::>(); + for mut used_id in all_ids { + while let Some(id) = self.aliases.get(&used_id) { + self.mutably_used_vars.insert(used_id); + used_id = *id; + } self.mutably_used_vars.insert(used_id); - used_id = *id; } - self.mutably_used_vars.insert(used_id); + self.mutably_used_vars } fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 53bcde680876e..39d374d0d27fd 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -9,8 +9,8 @@ use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, - QPath, TyKind, + BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, QPath, + TyKind, }; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index fd3985a5dafcf..932d6fe54d660 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -182,17 +182,17 @@ impl LateLintPass<'_> for NonCanonicalImpls { if block.stmts.is_empty() && let Some(expr) = block.expr - && let ExprKind::Call( - Expr { - kind: ExprKind::Path(some_path), - hir_id: some_hir_id, - .. - }, - [cmp_expr], - ) = expr.kind - && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) - // Fix #11178, allow `Self::cmp(self, ..)` too - && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified) + && expr_is_cmp(cx, &expr.kind, impl_item, &mut needs_fully_qualified) + { + } + // Fix #12683, allow [`needless_return`] here + else if block.expr.is_none() + && let Some(stmt) = block.stmts.first() + && let rustc_hir::StmtKind::Semi(Expr { + kind: ExprKind::Ret(Some(Expr { kind: ret_kind, .. })), + .. + }) = stmt.kind + && expr_is_cmp(cx, ret_kind, impl_item, &mut needs_fully_qualified) { } else { // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid @@ -245,6 +245,30 @@ impl LateLintPass<'_> for NonCanonicalImpls { } } +/// Return true if `expr_kind` is a `cmp` call. +fn expr_is_cmp<'tcx>( + cx: &LateContext<'tcx>, + expr_kind: &'tcx ExprKind<'tcx>, + impl_item: &ImplItem<'_>, + needs_fully_qualified: &mut bool, +) -> bool { + if let ExprKind::Call( + Expr { + kind: ExprKind::Path(some_path), + hir_id: some_hir_id, + .. + }, + [cmp_expr], + ) = expr_kind + { + is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) + // Fix #11178, allow `Self::cmp(self, ..)` too + && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, needs_fully_qualified) + } else { + false + } +} + /// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`. fn self_cmp_call<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index ff10a841aef1a..76d9cee18aa7f 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -5,9 +5,9 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; -use clippy_utils::{def_path_def_ids, in_constant}; -use rustc_data_structures::fx::FxHashSet; +use clippy_utils::ty::InteriorMut; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -52,8 +52,8 @@ declare_clippy_lint! { /// There're other enums plus associated constants cases that the lint cannot handle. /// /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issues - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + /// the interior mutable field is used or not. See issue + /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) /// /// ### Example /// ```no_run @@ -170,42 +170,22 @@ fn lint(cx: &LateContext<'_>, source: Source) { }); } -#[derive(Clone)] -pub struct NonCopyConst { +pub struct NonCopyConst<'tcx> { ignore_interior_mutability: Vec, - ignore_mut_def_ids: FxHashSet, + interior_mut: InteriorMut<'tcx>, } -impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); +impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); -impl NonCopyConst { +impl<'tcx> NonCopyConst<'tcx> { pub fn new(ignore_interior_mutability: Vec) -> Self { Self { ignore_interior_mutability, - ignore_mut_def_ids: FxHashSet::default(), + interior_mut: InteriorMut::default(), } } - fn is_ty_ignored(&self, ty: Ty<'_>) -> bool { - matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) - } - - fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) - } - - fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - if self.is_ty_ignored(ty) { - return false; - } + fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { match *ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. @@ -216,8 +196,7 @@ impl NonCopyConst { ty::Array(ty, _) => val .unwrap_branch() .iter() - .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Adt(def, _) if def.is_union() => false, + .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Adt(def, args) if def.is_enum() => { let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); @@ -230,24 +209,23 @@ impl NonCopyConst { .iter() .map(|field| field.ty(cx.tcx, args)), ) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty)) + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) }, ty::Adt(def, args) => val .unwrap_branch() .iter() .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Tuple(tys) => val .unwrap_branch() .iter() .zip(tys) - .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)), + .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), _ => false, } } - fn is_value_unfrozen_raw<'tcx>( - &self, + fn is_value_unfrozen_raw( cx: &LateContext<'tcx>, result: Result>, ErrorHandled>, ty: Ty<'tcx>, @@ -277,11 +255,11 @@ impl NonCopyConst { // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). matches!(err, ErrorHandled::TooGeneric(..)) }, - |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)), + |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)), ) } - fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::new(def_id, args); @@ -291,17 +269,17 @@ impl NonCopyConst { }; let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP); - self.is_value_unfrozen_raw(cx, result, ty) + Self::is_value_unfrozen_raw(cx, result, ty) } - fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); - self.is_value_unfrozen_raw(cx, result, ty) + Self::is_value_unfrozen_raw(cx, result, ty) } - pub fn const_eval_resolve<'tcx>( + pub fn const_eval_resolve( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, @@ -321,26 +299,17 @@ impl NonCopyConst { } } -impl<'tcx> LateLintPass<'tcx> for NonCopyConst { +impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - self.ignore_mut_def_ids.clear(); - let mut path = Vec::new(); - for ty in &self.ignore_interior_mutability { - path.extend(ty.split("::")); - for id in def_path_def_ids(cx, &path[..]) { - self.ignore_mut_def_ids.insert(id); - } - path.clear(); - } + self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(.., body_id) = it.kind { let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); if !ignored_macro(cx, it) - && !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_poly(cx, body_id, ty) + && self.interior_mut.is_interior_mut_ty(cx, ty) + && Self::is_value_unfrozen_poly(cx, body_id, ty) { lint(cx, Source::Item { item: it.span }); } @@ -354,7 +323,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) + if self.interior_mut.is_interior_mut_ty(cx, normalized) // When there's no default value, lint it only according to its type; // in other words, lint consts whose value *could* be unfrozen, not definitely is. // This feels inconsistent with how the lint treats generic types, @@ -367,7 +336,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // i.e. having an enum doesn't necessary mean a type has a frozen variant. // And, implementing it isn't a trivial task; it'll probably end up // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.map_or(true, |body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } @@ -409,8 +378,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty) - && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) - && self.is_value_unfrozen_poly(cx, *body_id, normalized) + && self.interior_mut.is_interior_mut_ty(cx, normalized) + && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } @@ -420,9 +389,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_poly(cx, *body_id, normalized) + if self.interior_mut.is_interior_mut_ty(cx, normalized) + && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } @@ -517,9 +485,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - if !self.is_ty_ignored(ty) - && Self::is_unfrozen(cx, ty) - && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) + if self.interior_mut.is_interior_mut_ty(cx, ty) + && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { lint(cx, Source::Expr { expr: expr.span }); } diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 96ea063aa74d6..7d6f26cde3e93 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -7,14 +7,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; -const INTEGER_METHODS: &[Symbol] = &[ +const DISALLOWED_INT_METHODS: &[Symbol] = &[ sym::saturating_div, sym::wrapping_div, sym::wrapping_rem, @@ -27,8 +26,8 @@ pub struct ArithmeticSideEffects { allowed_unary: FxHashSet, // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option, + disallowed_int_methods: FxHashSet, expr_span: Option, - integer_methods: FxHashSet, } impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); @@ -53,8 +52,8 @@ impl ArithmeticSideEffects { allowed_binary, allowed_unary, const_span: None, + disallowed_int_methods: DISALLOWED_INT_METHODS.iter().copied().collect(), expr_span: None, - integer_methods: INTEGER_METHODS.iter().copied().collect(), } } @@ -91,10 +90,10 @@ impl ArithmeticSideEffects { fn has_specific_allowed_type_and_operation<'tcx>( cx: &LateContext<'tcx>, lhs_ty: Ty<'tcx>, - op: &Spanned, + op: hir::BinOpKind, rhs_ty: Ty<'tcx>, ) -> bool { - let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem); + let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem); let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| { let tcx = cx.tcx; @@ -166,13 +165,35 @@ impl ArithmeticSideEffects { None } + /// Methods like `add_assign` are send to their `BinOps` references. + fn manage_sugar_methods<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + lhs: &'tcx hir::Expr<'_>, + ps: &hir::PathSegment<'_>, + rhs: &'tcx hir::Expr<'_>, + ) { + if ps.ident.name == sym::add || ps.ident.name == sym::add_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Add, lhs, rhs); + } else if ps.ident.name == sym::div || ps.ident.name == sym::div_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Div, lhs, rhs); + } else if ps.ident.name == sym::mul || ps.ident.name == sym::mul_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Mul, lhs, rhs); + } else if ps.ident.name == sym::rem || ps.ident.name == sym::rem_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Rem, lhs, rhs); + } else if ps.ident.name == sym::sub || ps.ident.name == sym::sub_assign { + self.manage_bin_ops(cx, expr, hir::BinOpKind::Sub, lhs, rhs); + } + } + /// Manages when the lint should be triggered. Operations in constant environments, hard coded - /// types, custom allowed types and non-constant operations that won't overflow are ignored. + /// types, custom allowed types and non-constant operations that don't overflow are ignored. fn manage_bin_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - op: &Spanned, + op: hir::BinOpKind, lhs: &'tcx hir::Expr<'_>, rhs: &'tcx hir::Expr<'_>, ) { @@ -180,7 +201,7 @@ impl ArithmeticSideEffects { return; } if !matches!( - op.node, + op, hir::BinOpKind::Add | hir::BinOpKind::Div | hir::BinOpKind::Mul @@ -204,7 +225,7 @@ impl ArithmeticSideEffects { return; } let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) { - if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op.node { + if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op { // At least for integers, shifts are already handled by the CTFE return; } @@ -213,7 +234,7 @@ impl ArithmeticSideEffects { Self::literal_integer(cx, actual_rhs), ) { (None, None) => false, - (None, Some(n)) => match (&op.node, n) { + (None, Some(n)) => match (&op, n) { // Division and module are always valid if applied to non-zero integers (hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true, // Adding or subtracting zeros is always a no-op @@ -223,7 +244,7 @@ impl ArithmeticSideEffects { => true, _ => false, }, - (Some(n), None) => match (&op.node, n) { + (Some(n), None) => match (&op, n) { // Adding or subtracting zeros is always a no-op (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) // Multiplication by 1 or 0 will never overflow @@ -249,6 +270,7 @@ impl ArithmeticSideEffects { &mut self, args: &'tcx [hir::Expr<'_>], cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, ps: &'tcx hir::PathSegment<'_>, receiver: &'tcx hir::Expr<'_>, ) { @@ -262,7 +284,8 @@ impl ArithmeticSideEffects { if !Self::is_integral(instance_ty) { return; } - if !self.integer_methods.contains(&ps.ident.name) { + self.manage_sugar_methods(cx, expr, receiver, ps, arg); + if !self.disallowed_int_methods.contains(&ps.ident.name) { return; } let (actual_arg, _) = peel_hir_expr_refs(arg); @@ -310,10 +333,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { } match &expr.kind { hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => { - self.manage_bin_ops(cx, expr, op, lhs, rhs); + self.manage_bin_ops(cx, expr, op.node, lhs, rhs); }, hir::ExprKind::MethodCall(ps, receiver, args, _) => { - self.manage_method_call(args, cx, ps, receiver); + self.manage_method_call(args, cx, expr, ps, receiver); }, hir::ExprKind::Unary(un_op, un_expr) => { self.manage_unary_ops(cx, expr, un_expr, *un_op); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index cc61ef9184cdc..2534e3c8468ce 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -11,9 +11,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirId, HirIdMap}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{ - self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, - ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, - TyKind, Unsafety, + self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind, + ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety, }; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; @@ -687,9 +686,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .filter_map(|(i, arg)| { let param = &body.params[arg.idx]; match param.pat.kind { - PatKind::Binding(BindingMode::NONE, id, _, None) - if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => - { + PatKind::Binding(BindingMode::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => { Some((id, i)) }, _ => { diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 4ad967589a543..1f1ce147ca241 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -14,8 +14,8 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, - Stmt, StmtKind, + BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, + StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs index a358881bf80ee..792d8fc88f0bb 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths}; use rustc_errors::Applicability; @@ -65,8 +65,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s /// Checks `vec![Vec::with_capacity(x); n]` fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(mac_call) = root_macro_call(expr.span) - && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id) + if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some() && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr) && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) && !len_expr.span.from_expansion() diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs index 14ca7a3f0042e..8d7f12af86e8a 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// fn size(&self) -> usize { /// // Note that `&self` as an argument is a `&&Foo`: Because `self` /// // is already a reference, `&self` is a double-reference. - /// // The return value of `size_of_val()` therefor is the + /// // The return value of `size_of_val()` therefore is the /// // size of the reference-type, not the size of `self`. /// std::mem::size_of_val(&self) /// } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 28c254537abdd..b0e25c02265b7 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, @@ -145,9 +145,7 @@ impl SlowVectorInit { // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro. // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an // empty vec - if expr.span.from_expansion() - && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro) - { + if expr.span.from_expansion() && matching_root_macro_call(cx, expr.span, sym::vec_macro).is_none() { return None; } diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index c1e24674e3e8c..4af3ee74d0eaf 100644 --- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -1,13 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::macro_backtrace; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{intravisit, ExprKind}; +use rustc_hir::{intravisit, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym::thread_local_macro; +use rustc_span::sym::{self, thread_local_macro}; declare_clippy_lint! { /// ### What it does @@ -69,6 +70,26 @@ fn is_thread_local_initializer( ) } +fn is_unreachable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(macro_call) = macro_backtrace(expr.span).next() + && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) + { + return (matches!( + diag_name, + sym::core_panic_macro + | sym::std_panic_macro + | sym::core_panic_2015_macro + | sym::std_panic_2015_macro + | sym::core_panic_2021_macro + ) && !cx.tcx.hir().is_inside_const_context(expr.hir_id)) + || matches!( + diag_name, + sym::unimplemented_macro | sym::todo_macro | sym::unreachable_macro | sym::unreachable_2015_macro + ); + } + false +} + #[inline] fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: &Msrv) -> bool { // Building MIR for `fn`s with unsatisfiable preds results in ICE. @@ -102,12 +123,17 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { // for details on this issue, see: // https://github.com/rust-lang/rust-clippy/pull/12276 && !cx.tcx.is_const_fn(defid) - && initializer_can_be_made_const(cx, defid, &self.msrv) - // we know that the function is const-qualifiable, so now - // we need only to get the initializer expression to span-lint it. && let ExprKind::Block(block, _) = body.value.kind && let Some(unpeeled) = block.expr && let ret_expr = peel_blocks(unpeeled) + // A common pattern around threadlocal! is to make the value unreachable + // to force an initialization before usage + // https://github.com/rust-lang/rust-clippy/issues/12637 + // we ensure that this is reachable before we check in mir + && !is_unreachable(cx, ret_expr) + && initializer_can_be_made_const(cx, defid, &self.msrv) + // we know that the function is const-qualifiable, so now + // we need only to get the initializer expression to span-lint it. && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }") && initializer_snippet != "thread_local! { ... }" { diff --git a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs index 59ae185c9de74..0361836cdec79 100644 --- a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub TO_STRING_TRAIT_IMPL, style, "check for direct implementations of `ToString`" diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 9468d367a9261..c05cd9ed59345 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -237,6 +237,7 @@ impl TraitBounds { } } + #[allow(clippy::mutable_key_type)] fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 0802cb2b7c75d..5e45ab211efd8 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -12,8 +12,8 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem, - TraitItemKind, TyKind, + Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitFn, + TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -420,7 +420,13 @@ impl<'tcx> LateLintPass<'tcx> for Types { TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { self.check_ty(cx, ty, context); }, - TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, context), + TraitItemKind::Fn(ref sig, trait_method) => { + // Check only methods without body + // Methods with body are covered by check_fn. + if let TraitFn::Required(_) = trait_method { + self.check_fn_decl(cx, sig.decl, context); + } + }, TraitItemKind::Type(..) => (), } } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 7f0769452c73e..4448c9ae3df79 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -7,8 +7,8 @@ use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, - PatKind, QPath, StmtKind, TyKind, + ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind, + QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 27ead55bf39cc..9edf7579d4827 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_trait_method}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -22,6 +22,7 @@ pub struct UselessVec { pub too_large_for_stack: u64, pub msrv: Msrv, pub span_to_lint_map: BTreeMap>, + pub allow_in_test: bool, } declare_clippy_lint! { @@ -57,6 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else { return; }; + if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { + return; + }; // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!` let callsite = expr.span.parent_callsite().unwrap_or(expr.span); diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index c46f0298cc8b7..a599415a2dd57 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -6,9 +6,7 @@ use clippy_utils::{get_parent_expr, path_to_local_id}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{ - BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, -}; +use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index d2bb719a517f5..ab883c25338ba 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.79" +version = "0.1.80" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 0395eb1449b48..529d20126b22c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -446,7 +446,18 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { use ForeignItemKind::*; match (l, r) { - (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ( + Static(box StaticForeignItem { + ty: lt, + mutability: lm, + expr: le, + }), + Static(box StaticForeignItem { + ty: rt, + mutability: rm, + expr: re, + }), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 5e242aea354a3..a49414a058b1c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2328,10 +2328,10 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)> +pub fn search_same(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)> where - Hash: Fn(&T) -> u64, - Eq: Fn(&T, &T) -> bool, + Hash: FnMut(&T) -> u64, + Eq: FnMut(&T, &T) -> bool, { match exprs { [a, b] if eq(a, b) => return vec![(a, b)], @@ -2505,8 +2505,9 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { with_test_item_names(tcx, tcx.parent_module(id), |names| { - tcx.hir() - .parent_iter(id) + let node = tcx.hir_node(id); + once((id, node)) + .chain(tcx.hir().parent_iter(id)) // Since you can nest functions we need to collect all until we leave // function scope .any(|(_id, node)| { @@ -2547,6 +2548,11 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { .any(|parent_id| is_cfg_test(tcx, parent_id)) } +/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]` +pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id) +} + /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let hir = tcx.hir(); diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index f166087dc3caa..257dd76ab15cf 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -119,10 +119,20 @@ pub fn macro_backtrace(span: Span) -> impl Iterator { /// If the macro backtrace of `span` has a macro call at the root expansion /// (i.e. not a nested macro call), returns `Some` with the `MacroCall` +/// +/// If you only want to check whether the root macro has a specific name, +/// consider using [`matching_root_macro_call`] instead. pub fn root_macro_call(span: Span) -> Option { macro_backtrace(span).last() } +/// A combination of [`root_macro_call`] and +/// [`is_diagnostic_item`](rustc_middle::ty::TyCtxt::is_diagnostic_item) that returns a `MacroCall` +/// at the root expansion if only it matches the given name. +pub fn matching_root_macro_call(cx: &LateContext<'_>, span: Span, name: Symbol) -> Option { + root_macro_call(span).filter(|mc| cx.tcx.is_diagnostic_item(name, mc.def_id)) +} + /// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node" /// produced by the macro call, as in [`first_node_in_macro`]. pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 456b8019e95cc..9bf068ee3cdee 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -19,8 +19,6 @@ pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "B pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; -pub const CORE_ITER_ENUMERATE_METHOD: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "enumerate"]; -pub const CORE_ITER_ENUMERATE_STRUCT: [&str; 5] = ["core", "iter", "adapters", "enumerate", "Enumerate"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; @@ -73,7 +71,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const SLICE_GET: [&str; 4] = ["core", "slice", "", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; @@ -81,7 +78,6 @@ pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; -pub const STR_BYTES: [&str; 4] = ["core", "str", "", "bytes"]; pub const STR_CHARS: [&str; 4] = ["core", "str", "", "chars"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; @@ -108,7 +104,6 @@ pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "Vec pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; -pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index a06a82c565300..23750ed4d1ba0 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -29,9 +29,10 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; +use std::collections::hash_map::Entry; use std::iter; -use crate::{match_def_path, path_res}; +use crate::{def_path_def_ids, match_def_path, path_res}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -1198,47 +1199,88 @@ pub fn make_normalized_projection<'tcx>( helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) } -/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`] -/// etc. -pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty), - ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty), - ty::Array(inner_ty, size) => { - size.try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(true, |u| u != 0) - && is_interior_mut_ty(cx, inner_ty) - }, - ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)), - ty::Adt(def, args) => { - // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to - // that of their type parameters. Note: we don't include `HashSet` and `HashMap` - // because they have no impl for `Hash` or `Ord`. - let def_id = def.did(); - let is_std_collection = [ - sym::Option, - sym::Result, - sym::LinkedList, - sym::Vec, - sym::VecDeque, - sym::BTreeMap, - sym::BTreeSet, - sym::Rc, - sym::Arc, - ] +/// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or +/// [`std::cell::RefCell`]. +#[derive(Default, Debug)] +pub struct InteriorMut<'tcx> { + ignored_def_ids: FxHashSet, + ignore_pointers: bool, + tys: FxHashMap, Option>, +} + +impl<'tcx> InteriorMut<'tcx> { + pub fn new(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self { + let ignored_def_ids = ignore_interior_mutability .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); - let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); - if is_std_collection || is_box { - // The type is mutable if any of its type parameters are - args.types().any(|ty| is_interior_mut_ty(cx, ty)) - } else { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx, cx.param_env) - } - }, - _ => false, + .flat_map(|ignored_ty| { + let path: Vec<&str> = ignored_ty.split("::").collect(); + def_path_def_ids(cx, path.as_slice()) + }) + .collect(); + + Self { + ignored_def_ids, + ..Self::default() + } + } + + pub fn without_pointers(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self { + Self { + ignore_pointers: true, + ..Self::new(cx, ignore_interior_mutability) + } + } + + /// Check if given type has inner mutability such as [`std::cell::Cell`] or + /// [`std::cell::RefCell`] etc. + pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match self.tys.entry(ty) { + Entry::Occupied(o) => return *o.get() == Some(true), + // Temporarily insert a `None` to break cycles + Entry::Vacant(v) => v.insert(None), + }; + + let interior_mut = match *ty.kind() { + ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.is_interior_mut_ty(cx, inner_ty), + ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.is_interior_mut_ty(cx, inner_ty), + ty::Array(inner_ty, size) => { + size.try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |u| u != 0) + && self.is_interior_mut_ty(cx, inner_ty) + }, + ty::Tuple(fields) => fields.iter().any(|ty| self.is_interior_mut_ty(cx, ty)), + ty::Adt(def, _) if def.is_unsafe_cell() => true, + ty::Adt(def, args) => { + let is_std_collection = matches!( + cx.tcx.get_diagnostic_name(def.did()), + Some( + sym::LinkedList + | sym::Vec + | sym::VecDeque + | sym::BTreeMap + | sym::BTreeSet + | sym::HashMap + | sym::HashSet + | sym::Arc + | sym::Rc + ) + ); + + if is_std_collection || def.is_box() { + // Include the types from std collections that are behind pointers internally + args.types().any(|ty| self.is_interior_mut_ty(cx, ty)) + } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() { + false + } else { + def.all_fields() + .any(|f| self.is_interior_mut_ty(cx, f.ty(cx.tcx, args))) + } + }, + _ => false, + }; + + self.tys.insert(ty, Some(interior_mut)); + interior_mut } } diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index 9a3a41e1d1ead..c8c734c3a7c9f 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.79" +version = "0.1.80" edition = "2021" publish = false diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 521c0d12983da..055f305eb8e18 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-04-18" +channel = "nightly-2024-05-02" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 32a31f5e08236..b06a11702ec86 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -4,6 +4,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] +use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling}; @@ -122,10 +123,11 @@ fn base_config(test_dir: &str) -> (Config, Args) { out_dir: target_dir.join("ui_test"), ..Config::rustc(Path::new("tests").join(test_dir)) }; - config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo { - rustfix: ui_test::RustfixMode::Everything, - })) - .into(); + config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo)).into(); + config + .comment_defaults + .base() + .set_custom("rustfix", RustfixMode::Everything); config.comment_defaults.base().diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); config.with_args(&args); let current_exe_path = env::current_exe().unwrap(); @@ -235,13 +237,12 @@ fn run_ui_cargo() { .push(("RUSTFLAGS".into(), Some("-Dwarnings".into()))); // We need to do this while we still have a rustc in the `program` field. config.fill_host_and_target().unwrap(); - config.dependencies_crate_manifest_path = None; config.program.program.set_file_name(if cfg!(windows) { "cargo-clippy.exe" } else { "cargo-clippy" }); - config.comment_defaults.base().edition = Default::default(); + config.comment_defaults.base().custom.clear(); config .comment_defaults diff --git a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs index 095e0d15448a7..3a8e3741e20c2 100644 --- a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs +++ b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs @@ -44,10 +44,18 @@ impl Deref for Counted { } } +#[derive(Hash, PartialEq, Eq)] +struct ContainsCounted { + inner: Counted, +} + // This is not linted because `"mut_key::Counted"` is in // `arc_like_types` in `clippy.toml` fn should_not_take_this_arg(_v: HashSet>) {} +fn indirect(_: HashMap) {} + fn main() { should_not_take_this_arg(HashSet::new()); + indirect(HashMap::new()); } diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs index 4ae75544c60c4..232bccf6a1543 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr index 120f5c35cb036..5ce2ed2ffaeec 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:27:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:26:5 | LL | x[index]; | ^^^^^^^^ @@ -9,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:41:5 | LL | v[0]; | ^^^^ @@ -17,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 | LL | v[10]; | ^^^^^ @@ -25,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:49:5 | LL | v[N]; | ^^^^ @@ -41,7 +41,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 | LL | v[M]; | ^^^^ diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 24645b61fdb07..722e9b3bc8d46 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -91,6 +92,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars @@ -171,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates allowed-idents-below-min-chars diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml b/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml new file mode 100644 index 0000000000000..230ca2d0ab72b --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml @@ -0,0 +1 @@ +allow-useless-vec-in-tests = true diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed new file mode 100644 index 0000000000000..08323a0dcc90f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&[1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs new file mode 100644 index 0000000000000..1f4b27c53429d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs @@ -0,0 +1,26 @@ +//@compile-flags: --test +#![warn(clippy::useless_vec)] +#![allow(clippy::unnecessary_operation, clippy::no_effect)] + +fn foo(_: &[u32]) {} + +fn main() { + foo(&vec![1_u32]); +} + +#[test] +pub fn in_test() { + foo(&vec![2_u32]); +} + +#[cfg(test)] +fn in_cfg_test() { + foo(&vec![3_u32]); +} + +#[cfg(test)] +mod mod1 { + fn in_cfg_test_mod() { + super::foo(&vec![4_u32]); + } +} diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr new file mode 100644 index 0000000000000..633110c3c8d92 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr @@ -0,0 +1,11 @@ +error: useless use of `vec!` + --> tests/ui-toml/useless_vec/useless_vec.rs:8:9 + | +LL | foo(&vec![1_u32]); + | ^^^^^^^^^^^^ help: you can use a slice directly: `&[1_u32]` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index b454c29aef4db..66d71f337f2f6 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -10,7 +10,7 @@ arithmetic_overflow, unconditional_panic )] -#![feature(const_mut_refs, inline_const)] +#![feature(const_mut_refs)] #![warn(clippy::arithmetic_side_effects)] extern crate proc_macro_derive; @@ -521,4 +521,14 @@ pub fn issue_11393() { example_rem(x, maybe_zero); } +pub fn issue_12318() { + use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; + let mut one: i32 = 1; + one.add_assign(1); + one.div_assign(1); + one.mul_assign(1); + one.rem_assign(1); + one.sub_assign(1); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 741c892a52cfc..8039c0bfa2484 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -715,5 +715,17 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | x % maybe_zero | ^^^^^^^^^^^^^^ -error: aborting due to 119 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:527:5 + | +LL | one.add_assign(1); + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:531:5 + | +LL | one.sub_assign(1); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 121 previous errors diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs index 3303eb1456785..6e6919cd295c4 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -9,6 +9,7 @@ use proc_macro::token_stream::IntoIter; use proc_macro::Delimiter::{self, Brace, Parenthesis}; use proc_macro::Spacing::{self, Alone, Joint}; use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; +use syn::spanned::Spanned; type Result = core::result::Result; @@ -124,6 +125,22 @@ fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Resul Ok(()) } +/// Takes an array repeat expression such as `[0_u32; 2]`, and return the tokens with 10 times the +/// original size, which turns to `[0_u32; 20]`. +#[proc_macro] +pub fn make_it_big(input: TokenStream) -> TokenStream { + let mut expr_repeat = syn::parse_macro_input!(input as syn::ExprRepeat); + let len_span = expr_repeat.len.span(); + if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len { + if let syn::Lit::Int(lit_int) = &expr_lit.lit { + let orig_val = lit_int.base10_parse::().expect("not a valid length parameter"); + let new_val = orig_val.saturating_mul(10); + expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val); + } + } + quote::quote!(#expr_repeat).into() +} + /// Within the item this attribute is attached to, an `inline!` macro is available which expands the /// contained tokens as though they came from a macro expansion. /// diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed index 167263d31df82..f7dad28b0369a 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs index f3f055eb7f065..d22871d2c8f2e 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs index 4da3833cbf5a0..5570e7cd6d2ee 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs @@ -158,7 +158,7 @@ trait BothOfCellAndGeneric { const INDIRECT: Cell<*const T>; fn function() { - let _ = &Self::DIRECT; + let _ = &Self::DIRECT; //~ ERROR: interior mutability let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } @@ -168,7 +168,7 @@ impl BothOfCellAndGeneric for Vec { const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); fn function() { - let _ = &Self::DIRECT; + let _ = &Self::DIRECT; //~ ERROR: interior mutability let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr index 582b744b49ff8..8602b46b0dcfe 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -75,6 +75,14 @@ LL | let _ = &Self::WRAPPED_SELF; | = help: assign this const to a local or static variable, and use the variable here +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/traits.rs:161:18 + | +LL | let _ = &Self::DIRECT; + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + error: a `const` item with interior mutability should not be borrowed --> tests/ui/borrow_interior_mutable_const/traits.rs:162:18 | @@ -83,6 +91,14 @@ LL | let _ = &Self::INDIRECT; | = help: assign this const to a local or static variable, and use the variable here +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/traits.rs:171:18 + | +LL | let _ = &Self::DIRECT; + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + error: a `const` item with interior mutability should not be borrowed --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 | @@ -123,5 +139,5 @@ LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index 6c2896b3aa0f2..1f2f57c2507db 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -65,6 +65,8 @@ fn main() { // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 let mut unnameable = Box::new(Option::default()); let _ = unnameable.insert(|| {}); + + let _ = Box::into_raw(Box::new(String::default())); } fn ret_ty_fn() -> Box { @@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } +struct X(T); + +impl X { + fn x(_: Box) {} + + fn same_generic_param() { + Self::x(Box::default()); + } +} + use std::io::{Read, Result}; impl Read for ImplementsDefault { diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index e19a62a90221e..addfebc24f58c 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -65,6 +65,8 @@ fn main() { // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 let mut unnameable = Box::new(Option::default()); let _ = unnameable.insert(|| {}); + + let _ = Box::into_raw(Box::new(String::default())); } fn ret_ty_fn() -> Box { @@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } +struct X(T); + +impl X { + fn x(_: Box) {} + + fn same_generic_param() { + Self::x(Box::new(T::default())); + } +} + use std::io::{Read, Result}; impl Read for ImplementsDefault { diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index f172a875dce47..39fd0d29bbf9a 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -55,5 +55,11 @@ error: `Box::new(_)` of default value LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` -error: aborting due to 9 previous errors +error: `Box::new(_)` of default value + --> tests/ui/box_default.rs:86:17 + | +LL | Self::x(Box::new(T::default())); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 215c008902d20..453d62ce60753 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -13,7 +13,8 @@ clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::identity_op )] fn main() { @@ -479,3 +480,21 @@ fn issue12506() -> usize { let bar: Result, u32> = Ok(Some(10)); bar.unwrap().unwrap() as usize } + +fn issue12721() { + fn x() -> u64 { + u64::MAX + } + + // Don't lint. + (255 & 999999u64) as u8; + // Don't lint. + let _ = ((x() & 255) & 999999) as u8; + // Don't lint. + let _ = (999999 & (x() & 255)) as u8; + + (256 & 999999u64) as u8; + //~^ ERROR: casting `u64` to `u8` may truncate the value + (255 % 999999u64) as u8; + //~^ ERROR: casting `u64` to `u8` may truncate the value +} diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 8b269c471765c..43c0d8f4ed738 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:22:5 + --> tests/ui/cast.rs:23:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:27:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:28:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:31:5 + --> tests/ui/cast.rs:32:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:34:5 + --> tests/ui/cast.rs:35:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:36:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:39:5 + --> tests/ui/cast.rs:40:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:41:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:41:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:46:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:47:5 + --> tests/ui/cast.rs:48:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:49:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:52:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:56:5 + --> tests/ui/cast.rs:57:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:61:22 + --> tests/ui/cast.rs:62:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:63:9 + --> tests/ui/cast.rs:64:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:65:9 + --> tests/ui/cast.rs:66:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:68:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:68:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:72:5 + --> tests/ui/cast.rs:73:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:75:5 + --> tests/ui/cast.rs:76:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:77:5 + --> tests/ui/cast.rs:78:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:80:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:81:5 + --> tests/ui/cast.rs:82:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:84:5 + --> tests/ui/cast.rs:85:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:88:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:92:5 + --> tests/ui/cast.rs:93:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:92:5 + --> tests/ui/cast.rs:93:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:97:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:101:5 + --> tests/ui/cast.rs:102:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:105:5 + --> tests/ui/cast.rs:106:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:109:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:113:5 + --> tests/ui/cast.rs:114:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:116:5 + --> tests/ui/cast.rs:117:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:127:5 + --> tests/ui/cast.rs:128:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:131:5 + --> tests/ui/cast.rs:132:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:132:5 + --> tests/ui/cast.rs:133:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:139:5 + --> tests/ui/cast.rs:140:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:154:5 + --> tests/ui/cast.rs:155:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:205:5 + --> tests/ui/cast.rs:206:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:219:5 + --> tests/ui/cast.rs:220:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:242:21 + --> tests/ui/cast.rs:243:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:244:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:286:21 + --> tests/ui/cast.rs:287:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:288:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:305:21 + --> tests/ui/cast.rs:306:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:324:21 + --> tests/ui/cast.rs:325:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:371:21 + --> tests/ui/cast.rs:372:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:382:13 + --> tests/ui/cast.rs:383:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:386:13 + --> tests/ui/cast.rs:387:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:398:9 + --> tests/ui/cast.rs:399:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:403:32 + --> tests/ui/cast.rs:404:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:405:5 + --> tests/ui/cast.rs:406:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:5 + --> tests/ui/cast.rs:407:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:411:5 + --> tests/ui/cast.rs:412:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:413:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:417:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:421:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:421:5 + --> tests/ui/cast.rs:422:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:426:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:427:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:429:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:430:5 + --> tests/ui/cast.rs:431:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:430:6 + --> tests/ui/cast.rs:431:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:433:5 + --> tests/ui/cast.rs:434:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:435:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:439:5 + --> tests/ui/cast.rs:440:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:441:5 + --> tests/ui/cast.rs:442:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:444:9 + --> tests/ui/cast.rs:445:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:445:9 + --> tests/ui/cast.rs:446:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:448:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:450:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:451:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:452:9 + --> tests/ui/cast.rs:453:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:455:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:456:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:457:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:9 + --> tests/ui/cast.rs:460:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:461:9 + --> tests/ui/cast.rs:462:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:469:21 + --> tests/ui/cast.rs:470:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:470:21 + --> tests/ui/cast.rs:471:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:471:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:480:5 + --> tests/ui/cast.rs:481:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,10 +702,34 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:480:5 + --> tests/ui/cast.rs:481:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 90 previous errors +error: casting `u64` to `u8` may truncate the value + --> tests/ui/cast.rs:496:5 + | +LL | (256 & 999999u64) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(256 & 999999u64); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: casting `u64` to `u8` may truncate the value + --> tests/ui/cast.rs:498:5 + | +LL | (255 % 999999u64) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(255 % 999999u64); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 92 previous errors diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed index 05d5b3d10eaf8..84dac431169ab 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[rustfmt::skip] - 5+3; + { 5+3; } } #[rustfmt::skip] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+29; + { 1+29; } } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[rustfmt::skip] - 1+30; + { 1+30; } } diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs index bc29e20210e8a..4ab5c70e13b5b 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[cfg_attr(rustfmt, rustfmt::skip)] - 5+3; + { 5+3; } } #[cfg_attr(rustfmt, rustfmt_skip)] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+29; + { 1+29; } } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[cfg_attr(rustfmt, rustfmt::skip)] - 1+30; + { 1+30; } } diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs index 7501fd2b0bd99..2264b560791aa 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.rs +++ b/src/tools/clippy/tests/ui/collapsible_match.rs @@ -4,7 +4,8 @@ clippy::needless_return, clippy::no_effect, clippy::single_match, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::let_unit_value )] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { @@ -238,13 +239,22 @@ fn negative_cases(res_opt: Result, String>, res_res: Result return, } - match make::>>() { + #[clippy::msrv = "1.52.0"] + let _ = match make::>>() { Some(val) => match val { E::A(val) | E::B(val) => foo(val), _ => return, }, _ => return, - } + }; + #[clippy::msrv = "1.53.0"] + let _ = match make::>>() { + Some(val) => match val { + E::A(val) | E::B(val) => foo(val), + _ => return, + }, + _ => return, + }; if let Ok(val) = res_opt { if let Some(n) = val { let _ = || { diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index 46b484ab05c4e..01944baee79af 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:13:20 + --> tests/ui/collapsible_match.rs:14:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:13:12 + --> tests/ui/collapsible_match.rs:14:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -21,7 +21,7 @@ LL | Some(n) => foo(n), = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:23:20 + --> tests/ui/collapsible_match.rs:24:20 | LL | Ok(val) => match val { | ____________________^ @@ -32,7 +32,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:23:12 + --> tests/ui/collapsible_match.rs:24:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -41,7 +41,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:33:9 + --> tests/ui/collapsible_match.rs:34:9 | LL | / if let Some(n) = val { LL | | @@ -50,7 +50,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:32:15 + --> tests/ui/collapsible_match.rs:33:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -58,7 +58,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:41:9 + --> tests/ui/collapsible_match.rs:42:9 | LL | / if let Some(n) = val { LL | | @@ -69,7 +69,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:40:15 + --> tests/ui/collapsible_match.rs:41:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -77,7 +77,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:53:9 + --> tests/ui/collapsible_match.rs:54:9 | LL | / match val { LL | | @@ -87,7 +87,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:52:15 + --> tests/ui/collapsible_match.rs:53:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -96,7 +96,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:63:13 + --> tests/ui/collapsible_match.rs:64:13 | LL | / if let Some(n) = val { LL | | @@ -105,7 +105,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:62:12 + --> tests/ui/collapsible_match.rs:63:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -113,7 +113,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:73:9 + --> tests/ui/collapsible_match.rs:74:9 | LL | / match val { LL | | @@ -123,7 +123,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:72:15 + --> tests/ui/collapsible_match.rs:73:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -132,7 +132,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:85:13 + --> tests/ui/collapsible_match.rs:86:13 | LL | / if let Some(n) = val { LL | | @@ -143,7 +143,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:84:12 + --> tests/ui/collapsible_match.rs:85:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -151,7 +151,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:97:20 + --> tests/ui/collapsible_match.rs:98:20 | LL | Ok(val) => match val { | ____________________^ @@ -162,7 +162,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:97:12 + --> tests/ui/collapsible_match.rs:98:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -171,7 +171,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:107:22 + --> tests/ui/collapsible_match.rs:108:22 | LL | Some(val) => match val { | ______________________^ @@ -182,7 +182,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:107:14 + --> tests/ui/collapsible_match.rs:108:14 | LL | Some(val) => match val { | ^^^ replace this binding @@ -190,8 +190,26 @@ LL | LL | Some(n) => foo(n), | ^^^^^^^ with this pattern +error: this `match` can be collapsed into the outer `match` + --> tests/ui/collapsible_match.rs:252:22 + | +LL | Some(val) => match val { + | ______________________^ +LL | | E::A(val) | E::B(val) => foo(val), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: the outer pattern can be modified to include the inner pattern + --> tests/ui/collapsible_match.rs:252:14 + | +LL | Some(val) => match val { + | ^^^ replace this binding +LL | E::A(val) | E::B(val) => foo(val), + | ^^^^^^^^^^^^^^^^^^^^^ with this pattern + error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:273:9 + --> tests/ui/collapsible_match.rs:283:9 | LL | / if let Some(u) = a { LL | | @@ -200,7 +218,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:272:27 + --> tests/ui/collapsible_match.rs:282:27 | LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding @@ -208,7 +226,7 @@ LL | if let Some(u) = a { | ^^^^^^^ with this pattern, prefixed by a: error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:282:9 + --> tests/ui/collapsible_match.rs:292:9 | LL | / if let Some(u) = a { LL | | @@ -217,12 +235,12 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:281:35 + --> tests/ui/collapsible_match.rs:291:35 | LL | if let Issue9647::A { a: Some(a), .. } = x { | ^ replace this binding LL | if let Some(u) = a { | ^^^^^^^ with this pattern -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.rs b/src/tools/clippy/tests/ui/collection_is_never_read.rs index bd281f7870cee..eeb10da3402a0 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.rs +++ b/src/tools/clippy/tests/ui/collection_is_never_read.rs @@ -222,3 +222,17 @@ fn supported_types() { //~^ ERROR: collection is never read x.push_front(1); } + +fn issue11783() { + struct Sender; + impl Sender { + fn send(&self, msg: String) -> Result<(), ()> { + // pretend to send message + println!("{msg}"); + Ok(()) + } + } + + let mut users: Vec = vec![]; + users.retain(|user| user.send("hello".to_string()).is_ok()); +} diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs index ae37a82e4f936..04e0de91ecfbf 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.rs +++ b/src/tools/clippy/tests/ui/const_is_empty.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::const_is_empty)] #![allow(clippy::needless_late_init, unused_must_use)] diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr index 0e09da77bb469..7f80b520b1a44 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.stderr +++ b/src/tools/clippy/tests/ui/const_is_empty.stderr @@ -1,5 +1,5 @@ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:6:8 + --> tests/ui/const_is_empty.rs:5:8 | LL | if "".is_empty() { | ^^^^^^^^^^^^^ @@ -8,151 +8,151 @@ LL | if "".is_empty() { = help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]` error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:9:8 + --> tests/ui/const_is_empty.rs:8:8 | LL | if "foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:15:8 + --> tests/ui/const_is_empty.rs:14:8 | LL | if b"".is_empty() { | ^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:18:8 + --> tests/ui/const_is_empty.rs:17:8 | LL | if b"foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:35:8 + --> tests/ui/const_is_empty.rs:34:8 | LL | if empty2.is_empty() { | ^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:38:8 + --> tests/ui/const_is_empty.rs:37:8 | LL | if non_empty2.is_empty() { | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:60:13 + --> tests/ui/const_is_empty.rs:59:13 | LL | let _ = EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:62:13 + --> tests/ui/const_is_empty.rs:61:13 | LL | let _ = NON_EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:64:13 + --> tests/ui/const_is_empty.rs:63:13 | LL | let _ = EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:66:13 + --> tests/ui/const_is_empty.rs:65:13 | LL | let _ = NON_EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:68:13 + --> tests/ui/const_is_empty.rs:67:13 | LL | let _ = EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:70:13 + --> tests/ui/const_is_empty.rs:69:13 | LL | let _ = EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:72:13 + --> tests/ui/const_is_empty.rs:71:13 | LL | let _ = EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:74:13 + --> tests/ui/const_is_empty.rs:73:13 | LL | let _ = NON_EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:76:13 + --> tests/ui/const_is_empty.rs:75:13 | LL | let _ = NON_EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:78:13 + --> tests/ui/const_is_empty.rs:77:13 | LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:80:13 + --> tests/ui/const_is_empty.rs:79:13 | LL | let _ = EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:82:13 + --> tests/ui/const_is_empty.rs:81:13 | LL | let _ = NON_EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:84:13 + --> tests/ui/const_is_empty.rs:83:13 | LL | let _ = EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:86:13 + --> tests/ui/const_is_empty.rs:85:13 | LL | let _ = NON_EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:88:13 + --> tests/ui/const_is_empty.rs:87:13 | LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:94:13 + --> tests/ui/const_is_empty.rs:93:13 | LL | let _ = value.is_empty(); | ^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:97:13 + --> tests/ui/const_is_empty.rs:96:13 | LL | let _ = x.is_empty(); | ^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:99:13 + --> tests/ui/const_is_empty.rs:98:13 | LL | let _ = "".is_empty(); | ^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:101:13 + --> tests/ui/const_is_empty.rs:100:13 | LL | let _ = b"".is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:155:13 + --> tests/ui/const_is_empty.rs:154:13 | LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs index b1fc3fb9d2511..ee2ae4f1a042e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs @@ -1,9 +1,10 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let _ = || { + let _ = #[coroutine] + || { yield; }; } diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs index adc53891ef54e..490073f97fb12 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs @@ -121,13 +121,12 @@ impl SelfType for AtomicUsize { // Even though a constant contains a generic type, if it also have an interior mutable type, // it should be linted at the definition site. trait BothOfCellAndGeneric { - // this is a false negative in the current implementation. - const DIRECT: Cell; + const DIRECT: Cell; //~ ERROR: interior mutable const INDIRECT: Cell<*const T>; //~ ERROR: interior mutable } impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); + const DIRECT: Cell = Cell::new(T::DEFAULT); //~ ERROR: interior mutable const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); } diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr index 328453efa244a..1d1e9e2002fa6 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr @@ -55,22 +55,34 @@ LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:126:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 + | +LL | const DIRECT: Cell; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> tests/ui/declare_interior_mutable_const/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:142:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:129:5 + | +LL | const DIRECT: Cell = Cell::new(T::DEFAULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> tests/ui/declare_interior_mutable_const/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:148:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 9a701a2cbcfb8..13c883409bf6e 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs @@ -71,3 +71,8 @@ mod tests { } } } + +#[test] +fn test_with_disallowed_name() { + let foo = 0; +} diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index 0649a6cb0f3ec..f913ae0bb5067 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -54,7 +54,7 @@ help: replace the `Into` implementation with `From` LL ~ impl core::convert::From for bool { LL ~ fn from(mut val: crate::ExplicitPaths) -> Self { LL ~ let in_closure = || val.0; -LL | +LL | LL ~ val.0 = false; LL ~ val.0 | diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index 27ee2f91594bf..2e726141649e7 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -1,6 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 5f62ec9b55655..386f91becf14d 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:16:20 + --> tests/ui/indexing_slicing_index.rs:15:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:48:5 + --> tests/ui/indexing_slicing_index.rs:47:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:29:5 + --> tests/ui/indexing_slicing_index.rs:28:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:32:5 + --> tests/ui/indexing_slicing_index.rs:31:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:34:5 + --> tests/ui/indexing_slicing_index.rs:33:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:45:14 + --> tests/ui/indexing_slicing_index.rs:44:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:55:5 + --> tests/ui/indexing_slicing_index.rs:54:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:58:5 + --> tests/ui/indexing_slicing_index.rs:57:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:60:5 + --> tests/ui/indexing_slicing_index.rs:59:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:62:5 + --> tests/ui/indexing_slicing_index.rs:61:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:70:5 + --> tests/ui/indexing_slicing_index.rs:69:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:73:5 + --> tests/ui/indexing_slicing_index.rs:72:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:75:5 + --> tests/ui/indexing_slicing_index.rs:74:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:79:13 + --> tests/ui/indexing_slicing_index.rs:78:13 | LL | let _ = x[4]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed index aa8c3021b9708..1e87859f45263 100644 --- a/src/tools/clippy/tests/ui/large_futures.fixed +++ b/src/tools/clippy/tests/ui/large_futures.fixed @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs index fc6ea458d3dbd..3f4ea2ebf8bbe 100644 --- a/src/tools/clippy/tests/ui/large_futures.rs +++ b/src/tools/clippy/tests/ui/large_futures.rs @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/clippy/tests/ui/large_futures.stderr b/src/tools/clippy/tests/ui/large_futures.stderr index 5709c7b77a0a5..00082e579c597 100644 --- a/src/tools/clippy/tests/ui/large_futures.stderr +++ b/src/tools/clippy/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:11:9 + --> tests/ui/large_futures.rs:10:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await; = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:15:5 + --> tests/ui/large_futures.rs:14:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:20:9 + --> tests/ui/large_futures.rs:19:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:13 + --> tests/ui/large_futures.rs:24:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:33:5 + --> tests/ui/large_futures.rs:32:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:35:5 + --> tests/ui/large_futures.rs:34:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:48:5 + --> tests/ui/large_futures.rs:47:5 | LL | / async { LL | | @@ -59,7 +59,7 @@ LL + }) | error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:60:13 + --> tests/ui/large_futures.rs:59:13 | LL | / async { LL | | let x = [0i32; 1024 * 16]; diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs index d5c4f95f8c422..6bcaf481c9f7e 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.rs +++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::large_stack_arrays)] #![allow(clippy::large_enum_variant)] +extern crate proc_macros; + #[derive(Clone, Copy)] struct S { pub data: [u64; 32], @@ -55,3 +58,48 @@ fn main() { [(); 20_000_000], ); } + +#[allow(clippy::useless_vec)] +fn issue_12586() { + macro_rules! dummy { + ($n:expr) => { + $n + }; + // Weird rule to test help messages. + ($a:expr => $b:expr) => { + [$a, $b, $a, $b] + //~^ ERROR: allocating a local array larger than 512000 bytes + }; + ($id:ident; $n:literal) => { + dummy!(::std::vec![$id;$n]) + }; + ($($id:expr),+ $(,)?) => { + ::std::vec![$($id),*] + } + } + macro_rules! create_then_move { + ($id:ident; $n:literal) => {{ + let _x_ = [$id; $n]; + //~^ ERROR: allocating a local array larger than 512000 bytes + _x_ + }}; + } + + let x = [0u32; 50_000]; + let y = vec![x, x, x, x, x]; + let y = vec![dummy![x, x, x, x, x]]; + let y = vec![dummy![[x, x, x, x, x]]]; + let y = dummy![x, x, x, x, x]; + let y = [x, x, dummy!(x), x, x]; + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = dummy![x => x]; + let y = dummy![x;5]; + let y = dummy!(vec![dummy![x, x, x, x, x]]); + let y = dummy![[x, x, x, x, x]]; + //~^ ERROR: allocating a local array larger than 512000 bytes + + let y = proc_macros::make_it_big!([x; 1]); + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = vec![proc_macros::make_it_big!([x; 10])]; + let y = vec![create_then_move![x; 5]; 5]; +} diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr index 007ca61c2de13..06294ee8b8cb1 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr @@ -1,5 +1,5 @@ error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:29:14 + --> tests/ui/large_stack_arrays.rs:32:14 | LL | let _x = [build(); 3]; | ^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _x = [build(); 3]; = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:32:14 + --> tests/ui/large_stack_arrays.rs:35:14 | LL | let _y = [build(), build(), build()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _y = [build(), build(), build()]; = help: consider allocating on the heap with `vec![build(), build(), build()].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:38:9 + --> tests/ui/large_stack_arrays.rs:41:9 | LL | [0u32; 20_000_000], | ^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | [0u32; 20_000_000], = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:40:9 + --> tests/ui/large_stack_arrays.rs:43:9 | LL | [S { data: [0; 32] }; 5000], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | [S { data: [0; 32] }; 5000], = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:42:9 + --> tests/ui/large_stack_arrays.rs:45:9 | LL | [Some(""); 20_000_000], | ^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | [Some(""); 20_000_000], = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:44:9 + --> tests/ui/large_stack_arrays.rs:47:9 | LL | [E::T(0); 5000], | ^^^^^^^^^^^^^^^ @@ -49,12 +49,56 @@ LL | [E::T(0); 5000], = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()` error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:46:9 + --> tests/ui/large_stack_arrays.rs:49:9 | LL | [0u8; usize::MAX], | ^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` -error: aborting due to 7 previous errors +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:93:13 + | +LL | let y = [x, x, dummy!(x), x, x]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:70:13 + | +LL | [$a, $b, $a, $b] + | ^^^^^^^^^^^^^^^^ +... +LL | let y = dummy![x => x]; + | -------------- in this macro invocation + | + = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:98:20 + | +LL | let y = dummy![[x, x, x, x, x]]; + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:101:39 + | +LL | let y = proc_macros::make_it_big!([x; 1]); + | ^^^^^^ + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:82:23 + | +LL | let _x_ = [$id; $n]; + | ^^^^^^^^^ +... +LL | let y = vec![create_then_move![x; 5]; 5]; + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `create_then_move` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/let_and_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr index f614a5739a860..ff5962ec196e6 100644 --- a/src/tools/clippy/tests/ui/let_and_return.stderr +++ b/src/tools/clippy/tests/ui/let_and_return.stderr @@ -71,7 +71,7 @@ LL | result help: return the expression directly | LL ~ -LL | +LL | LL ~ (match self { LL + E::A(x) => x, LL + E::B(x) => x, diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs index f3e95d6807d33..80781ecda721a 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.rs +++ b/src/tools/clippy/tests/ui/manual_float_methods.rs @@ -2,7 +2,6 @@ //@aux-build:proc_macros.rs #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] -#![feature(inline_const)] #[macro_use] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr index dae96839262d1..930df0b97cb3f 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.stderr +++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr @@ -1,5 +1,5 @@ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:23:8 + --> tests/ui/manual_float_methods.rs:22:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` @@ -8,7 +8,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:24:8 + --> tests/ui/manual_float_methods.rs:23:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:25:8 + --> tests/ui/manual_float_methods.rs:24:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:26:8 + --> tests/ui/manual_float_methods.rs:25:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +54,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:28:8 + --> tests/ui/manual_float_methods.rs:27:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:29:8 + --> tests/ui/manual_float_methods.rs:28:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed index 9c4bd335ad8ba..a72caa3a37ee6 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed @@ -55,3 +55,30 @@ fn msrv_1_47() { const FOO: bool = 'x'.is_ascii_digit(); const BAR: bool = 'x'.is_ascii_hexdigit(); } + +#[allow(clippy::deref_addrof, clippy::needless_borrow)] +fn with_refs() { + let cool_letter = &&'g'; + cool_letter.is_ascii_digit(); + cool_letter.is_ascii_lowercase(); +} + +fn generics() { + fn a(u: &U) -> bool + where + char: PartialOrd, + U: PartialOrd + ?Sized, + { + ('A'..='Z').contains(u) + } + + fn take_while(cond: F) + where + Item: Sized, + F: Fn(Item) -> bool, + { + } + take_while(|c: char| c.is_ascii_uppercase()); + take_while(|c: u8| c.is_ascii_uppercase()); + take_while(|c: char| c.is_ascii_uppercase()); +} diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs index 785943cd24d2c..bb6e2a317da16 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs @@ -55,3 +55,30 @@ fn msrv_1_47() { const FOO: bool = matches!('x', '0'..='9'); const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); } + +#[allow(clippy::deref_addrof, clippy::needless_borrow)] +fn with_refs() { + let cool_letter = &&'g'; + ('0'..='9').contains(&&cool_letter); + ('a'..='z').contains(*cool_letter); +} + +fn generics() { + fn a(u: &U) -> bool + where + char: PartialOrd, + U: PartialOrd + ?Sized, + { + ('A'..='Z').contains(u) + } + + fn take_while(cond: F) + where + Item: Sized, + F: Fn(Item) -> bool, + { + } + take_while(|c| ('A'..='Z').contains(&c)); + take_while(|c| (b'A'..=b'Z').contains(&c)); + take_while(|c: char| ('A'..='Z').contains(&c)); +} diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr index 3632077ec8086..a93ccace28a6e 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr @@ -133,5 +133,45 @@ error: manual check for common ascii range LL | const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` -error: aborting due to 22 previous errors +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:62:5 + | +LL | ('0'..='9').contains(&&cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()` + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:63:5 + | +LL | ('a'..='z').contains(*cool_letter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()` + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:81:20 + | +LL | take_while(|c| ('A'..='Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | take_while(|c: char| c.is_ascii_uppercase()); + | ~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:82:20 + | +LL | take_while(|c| (b'A'..=b'Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | take_while(|c: u8| c.is_ascii_uppercase()); + | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:83:26 + | +LL | take_while(|c: char| ('A'..='Z').contains(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()` + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/manual_strip.stderr b/src/tools/clippy/tests/ui/manual_strip.stderr index d2d4f765310b9..a70c988a0549e 100644 --- a/src/tools/clippy/tests/ui/manual_strip.stderr +++ b/src/tools/clippy/tests/ui/manual_strip.stderr @@ -17,7 +17,7 @@ LL ~ if let Some() = s.strip_prefix("ab") { LL ~ str::to_string(); LL | LL ~ .to_string(); -LL | +LL | LL ~ str::to_string(); LL ~ .to_string(); | @@ -39,7 +39,7 @@ LL ~ if let Some() = s.strip_suffix("bc") { LL ~ str::to_string(); LL | LL ~ .to_string(); -LL | +LL | LL ~ str::to_string(); LL ~ .to_string(); | diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed index 861764a2aeeb9..b84b3dc349ec3 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_i8; // should be i8 let fail31 = 240_u8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_i16; let fail34 = 0xABCD_u16; let ok35 = 0x12345_16; diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs index 4a15c335fd893..a47a736067a85 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_8; // should be i8 let fail31 = 240_8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_16; let fail34 = 0xABCD_16; let ok35 = 0x12345_16; diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs index 2d70bfd4c770c..81d8732b3b210 100644 --- a/src/tools/clippy/tests/ui/mut_key.rs +++ b/src/tools/clippy/tests/ui/mut_key.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; -//@no-rustfix + struct Key(AtomicUsize); impl Clone for Key { @@ -77,8 +77,6 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::<&mut Cell, usize>::new(); //~^ ERROR: mutable key type - let _map = HashMap::<&mut usize, usize>::new(); - //~^ ERROR: mutable key type // Collection types from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type @@ -92,8 +90,6 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::>>, usize>::new(); //~^ ERROR: mutable key type - let _map = HashMap::, usize>::new(); - //~^ ERROR: mutable key type // Smart pointers from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type @@ -101,4 +97,8 @@ fn main() { //~^ ERROR: mutable key type let _map = HashMap::>, usize>::new(); //~^ ERROR: mutable key type + + // Not interior mutability + let _map = HashMap::<&mut usize, usize>::new(); + let _map = HashMap::, usize>::new(); } diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr index e54c3075d4f13..5ad9aad2d0a5a 100644 --- a/src/tools/clippy/tests/ui/mut_key.stderr +++ b/src/tools/clippy/tests/ui/mut_key.stderr @@ -38,70 +38,58 @@ LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:80:5 - | -LL | let _map = HashMap::<&mut usize, usize>::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: mutable key type - --> tests/ui/mut_key.rs:83:5 + --> tests/ui/mut_key.rs:81:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:85:5 + --> tests/ui/mut_key.rs:83:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:87:5 + --> tests/ui/mut_key.rs:85:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:89:5 + --> tests/ui/mut_key.rs:87:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:91:5 + --> tests/ui/mut_key.rs:89:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:93:5 + --> tests/ui/mut_key.rs:91:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:95:5 - | -LL | let _map = HashMap::, usize>::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: mutable key type - --> tests/ui/mut_key.rs:98:5 + --> tests/ui/mut_key.rs:94:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:100:5 + --> tests/ui/mut_key.rs:96:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> tests/ui/mut_key.rs:102:5 + --> tests/ui/mut_key.rs:98:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed index 8c0e7ba762786..2362314290e61 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed @@ -113,6 +113,10 @@ fn should_not_lint() { let _ = v.iter().for_each(|elem| { acc += elem; }); + // `for_each` has a closure with an unsafe block. + v.iter().for_each(|elem| unsafe { + acc += elem; + }); } fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs index cdc903a636c99..5b1186daa229b 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs @@ -113,6 +113,10 @@ fn should_not_lint() { let _ = v.iter().for_each(|elem| { acc += elem; }); + // `for_each` has a closure with an unsafe block. + v.iter().for_each(|elem| unsafe { + acc += elem; + }); } fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index a92197fb0af5c..3f5f55f400208 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -44,18 +44,13 @@ fn non_mut_ref(_: &Vec) {} struct Bar; impl Bar { - // Should not warn on `&mut self`. fn bar(&mut self) {} + //~^ ERROR: this argument is a mutable reference, but not used mutably fn mushroom(&self, vec: &mut Vec) -> usize { //~^ ERROR: this argument is a mutable reference, but not used mutably vec.len() } - - fn badger(&mut self, vec: &mut Vec) -> usize { - //~^ ERROR: this argument is a mutable reference, but not used mutably - vec.len() - } } trait Babar { @@ -307,6 +302,41 @@ fn filter_copy(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) move |&item| predicate(item) } +trait MutSelfTrait { + // Should not warn since it's a trait method. + fn mut_self(&mut self); +} + +struct MutSelf { + a: u32, +} + +impl MutSelf { + fn bar(&mut self) {} + //~^ ERROR: this argument is a mutable reference, but not used mutably + async fn foo(&mut self, u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + //~| ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; + } + async fn foo2(&mut self, u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + self.a += 1; + *u += 1; + } + .await; + } +} + +impl MutSelfTrait for MutSelf { + // Should not warn since it's a trait method. + fn mut_self(&mut self) {} +} + // `is_from_proc_macro` stress tests fn _empty_tup(x: &mut (())) {} fn _single_tup(x: &mut ((i32,))) {} diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 89dad3e60b143..21ca393dcb63c 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -14,73 +14,73 @@ LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:50:29 + --> tests/ui/needless_pass_by_ref_mut.rs:47:12 | -LL | fn mushroom(&self, vec: &mut Vec) -> usize { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` +LL | fn bar(&mut self) {} + | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:55:31 + --> tests/ui/needless_pass_by_ref_mut.rs:50:29 | -LL | fn badger(&mut self, vec: &mut Vec) -> usize { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` +LL | fn mushroom(&self, vec: &mut Vec) -> usize { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:132:16 + --> tests/ui/needless_pass_by_ref_mut.rs:127:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:136:16 + --> tests/ui/needless_pass_by_ref_mut.rs:131:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:140:16 + --> tests/ui/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:144:16 + --> tests/ui/needless_pass_by_ref_mut.rs:139:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:148:24 + --> tests/ui/needless_pass_by_ref_mut.rs:143:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:152:24 + --> tests/ui/needless_pass_by_ref_mut.rs:147:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:156:32 + --> tests/ui/needless_pass_by_ref_mut.rs:151:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:160:24 + --> tests/ui/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:160:45 + --> tests/ui/needless_pass_by_ref_mut.rs:155:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:194:16 + --> tests/ui/needless_pass_by_ref_mut.rs:189:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:200:20 + --> tests/ui/needless_pass_by_ref_mut.rs:195:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:214:39 + --> tests/ui/needless_pass_by_ref_mut.rs:209:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:222:26 + --> tests/ui/needless_pass_by_ref_mut.rs:217:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:241:34 + --> tests/ui/needless_pass_by_ref_mut.rs:236:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,15 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:253:25 - | -LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility - -error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:260:20 + --> tests/ui/needless_pass_by_ref_mut.rs:255:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +124,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:271:26 + --> tests/ui/needless_pass_by_ref_mut.rs:266:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -140,64 +132,88 @@ LL | pub async fn closure4(n: &mut usize) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:311:18 + --> tests/ui/needless_pass_by_ref_mut.rs:315:12 + | +LL | fn bar(&mut self) {} + | ^^^^^^^^^ help: consider changing to: `&self` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:317:18 + | +LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^^ help: consider changing to: `&self` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:317:45 + | +LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:325:46 + | +LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut.rs:341:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:312:19 + --> tests/ui/needless_pass_by_ref_mut.rs:342:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:313:18 + --> tests/ui/needless_pass_by_ref_mut.rs:343:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:314:11 + --> tests/ui/needless_pass_by_ref_mut.rs:344:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:23 + --> tests/ui/needless_pass_by_ref_mut.rs:346:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:317:20 + --> tests/ui/needless_pass_by_ref_mut.rs:347:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:318:18 + --> tests/ui/needless_pass_by_ref_mut.rs:348:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:319:25 + --> tests/ui/needless_pass_by_ref_mut.rs:349:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:320:20 + --> tests/ui/needless_pass_by_ref_mut.rs:350:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:321:20 + --> tests/ui/needless_pass_by_ref_mut.rs:351:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` -error: aborting due to 31 previous errors +error: aborting due to 34 previous errors diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed new file mode 100644 index 0000000000000..3c2576213cd77 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed @@ -0,0 +1,24 @@ +// If both `inner_async3` and `inner_async4` are present, aliases are declared after +// they're used in `inner_async4` for some reasons... This test ensures that no +// only `v` is marked as not used mutably in `inner_async4`. + +#![allow(clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] + +pub async fn inner_async3(x: &i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *y += 1; + } + .await; +} + +pub async fn inner_async4(u: &mut i32, v: &u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs new file mode 100644 index 0000000000000..34b0b564deb8e --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs @@ -0,0 +1,24 @@ +// If both `inner_async3` and `inner_async4` are present, aliases are declared after +// they're used in `inner_async4` for some reasons... This test ensures that no +// only `v` is marked as not used mutably in `inner_async4`. + +#![allow(clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] + +pub async fn inner_async3(x: &mut i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *y += 1; + } + .await; +} + +pub async fn inner_async4(u: &mut i32, v: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *u += 1; + } + .await; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr new file mode 100644 index 0000000000000..c875360322568 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr @@ -0,0 +1,20 @@ +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:8:30 + | +LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` + | + = warning: changing this function will impact semver compatibility + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` + +error: this argument is a mutable reference, but not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:16:43 + | +LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + | + = warning: changing this function will impact semver compatibility + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs index 92f173d9db4a3..93c69209c6980 100644 --- a/src/tools/clippy/tests/ui/never_loop.rs +++ b/src/tools/clippy/tests/ui/never_loop.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, try_blocks)] +#![feature(try_blocks)] #![allow( clippy::eq_op, clippy::single_match, diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed index db55cc094e3ac..d444a753697f0 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed @@ -142,3 +142,21 @@ impl PartialOrd for H { Some(Ord::cmp(self, other)) } } + +// #12683, do not lint + +#[derive(Eq, PartialEq)] +struct I(u32); + +impl Ord for I { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for I { + #[allow(clippy::needless_return)] + fn partial_cmp(&self, other: &Self) -> Option { + return Some(self.cmp(other)); + } +} diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs index 52f4b85b9172f..dc6c4354604d0 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs @@ -146,3 +146,21 @@ impl PartialOrd for H { Some(Ord::cmp(self, other)) } } + +// #12683, do not lint + +#[derive(Eq, PartialEq)] +struct I(u32); + +impl Ord for I { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for I { + #[allow(clippy::needless_return)] + fn partial_cmp(&self, other: &Self) -> Option { + return Some(self.cmp(other)); + } +} diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs index dccfbd409e503..2bbf5792ec4c2 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.rs +++ b/src/tools/clippy/tests/ui/panicking_macros.rs @@ -1,5 +1,4 @@ #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::let_unit_value)] -#![feature(inline_const)] #![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)] extern crate core; diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr index 06025859c0c6d..7c0f0a7d37644 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.stderr +++ b/src/tools/clippy/tests/ui/panicking_macros.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:23:5 + --> tests/ui/panicking_macros.rs:22:5 | LL | panic!(); | ^^^^^^^^ @@ -8,19 +8,19 @@ LL | panic!(); = help: to override `-D warnings` add `#[allow(clippy::panic)]` error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:26:5 + --> tests/ui/panicking_macros.rs:25:5 | LL | panic!("message"); | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:28:5 + --> tests/ui/panicking_macros.rs:27:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:35:5 + --> tests/ui/panicking_macros.rs:34:5 | LL | todo!(); | ^^^^^^^ @@ -29,19 +29,19 @@ LL | todo!(); = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:38:5 + --> tests/ui/panicking_macros.rs:37:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:40:5 + --> tests/ui/panicking_macros.rs:39:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:47:5 + --> tests/ui/panicking_macros.rs:46:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ @@ -50,19 +50,19 @@ LL | unimplemented!(); = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:50:5 + --> tests/ui/panicking_macros.rs:49:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:52:5 + --> tests/ui/panicking_macros.rs:51:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:59:5 + --> tests/ui/panicking_macros.rs:58:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -71,37 +71,37 @@ LL | unreachable!(); = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:62:5 + --> tests/ui/panicking_macros.rs:61:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:64:5 + --> tests/ui/panicking_macros.rs:63:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:71:5 + --> tests/ui/panicking_macros.rs:70:5 | LL | panic!(); | ^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:73:5 + --> tests/ui/panicking_macros.rs:72:5 | LL | todo!(); | ^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:75:5 + --> tests/ui/panicking_macros.rs:74:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:77:5 + --> tests/ui/panicking_macros.rs:76:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.fixed b/src/tools/clippy/tests/ui/readonly_write_lock.fixed index 76f4a43ae5300..4db13482ac786 100644 --- a/src/tools/clippy/tests/ui/readonly_write_lock.fixed +++ b/src/tools/clippy/tests/ui/readonly_write_lock.fixed @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs index 3d1d3855fe129..66ba1b2d6969e 100644 --- a/src/tools/clippy/tests/ui/readonly_write_lock.rs +++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed index ded91e0837699..ed4b1c219150e 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.fixed +++ b/src/tools/clippy/tests/ui/redundant_guards.fixed @@ -136,6 +136,18 @@ fn f(s: Option) { } } +fn not_matches() { + match Some(42) { + // The pattern + guard is not equivalent to `Some(42)` because of the `panic!` + Some(v) + if match v { + 42 => true, + _ => panic!(), + } => {}, + _ => {}, + } +} + struct S { a: usize, } diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs index 2aaa2ace3982e..adbc4ed16cd7b 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.rs +++ b/src/tools/clippy/tests/ui/redundant_guards.rs @@ -136,6 +136,18 @@ fn f(s: Option) { } } +fn not_matches() { + match Some(42) { + // The pattern + guard is not equivalent to `Some(42)` because of the `panic!` + Some(v) + if match v { + 42 => true, + _ => panic!(), + } => {}, + _ => {}, + } +} + struct S { a: usize, } diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr index 01ca91fcd09e8..fd12e08328231 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.stderr +++ b/src/tools/clippy/tests/ui/redundant_guards.stderr @@ -132,7 +132,7 @@ LL + 1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:174:28 + --> tests/ui/redundant_guards.rs:186:28 | LL | Some(ref x) if x == &1 => {}, | ^^^^^^^ @@ -144,7 +144,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:175:28 + --> tests/ui/redundant_guards.rs:187:28 | LL | Some(ref x) if &1 == x => {}, | ^^^^^^^ @@ -156,7 +156,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:176:28 + --> tests/ui/redundant_guards.rs:188:28 | LL | Some(ref x) if let &2 = x => {}, | ^^^^^^^^^^ @@ -168,7 +168,7 @@ LL + Some(2) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:177:28 + --> tests/ui/redundant_guards.rs:189:28 | LL | Some(ref x) if matches!(x, &3) => {}, | ^^^^^^^^^^^^^^^ @@ -180,7 +180,7 @@ LL + Some(3) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:197:32 + --> tests/ui/redundant_guards.rs:209:32 | LL | B { ref c, .. } if c == &1 => {}, | ^^^^^^^ @@ -192,7 +192,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:198:32 + --> tests/ui/redundant_guards.rs:210:32 | LL | B { ref c, .. } if &1 == c => {}, | ^^^^^^^ @@ -204,7 +204,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:199:32 + --> tests/ui/redundant_guards.rs:211:32 | LL | B { ref c, .. } if let &1 = c => {}, | ^^^^^^^^^^ @@ -216,7 +216,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:200:32 + --> tests/ui/redundant_guards.rs:212:32 | LL | B { ref c, .. } if matches!(c, &1) => {}, | ^^^^^^^^^^^^^^^ @@ -228,7 +228,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:210:26 + --> tests/ui/redundant_guards.rs:222:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL + Some(Some("")) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:221:26 + --> tests/ui/redundant_guards.rs:233:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -252,7 +252,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:226:26 + --> tests/ui/redundant_guards.rs:238:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -264,7 +264,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:237:26 + --> tests/ui/redundant_guards.rs:249:26 | LL | Some(Some(x)) if x.starts_with(&[]) => {}, | ^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL + Some(Some([..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:242:26 + --> tests/ui/redundant_guards.rs:254:26 | LL | Some(Some(x)) if x.starts_with(&[1]) => {}, | ^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL + Some(Some([1, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:247:26 + --> tests/ui/redundant_guards.rs:259:26 | LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^^^ @@ -300,7 +300,7 @@ LL + Some(Some([1, 2, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:252:26 + --> tests/ui/redundant_guards.rs:264:26 | LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL + Some(Some([.., 1, 2])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:274:18 + --> tests/ui/redundant_guards.rs:286:18 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ @@ -324,7 +324,7 @@ LL + "" => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:293:22 + --> tests/ui/redundant_guards.rs:305:22 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs index f6909828aa9a7..d21aa240b2df9 100644 --- a/src/tools/clippy/tests/ui/redundant_locals.rs +++ b/src/tools/clippy/tests/ui/redundant_locals.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)] #![warn(clippy::redundant_locals)] -#![feature(async_closure, coroutines)] +#![feature(async_closure, coroutines, stmt_expr_attributes)] extern crate proc_macros; use proc_macros::{external, with_span}; @@ -191,14 +191,20 @@ fn issue12225() { let v4 = v4; dbg!(&v4); }); - assert_static(static || { - let v5 = v5; - yield; - }); - assert_static(|| { - let v6 = v6; - yield; - }); + assert_static( + #[coroutine] + static || { + let v5 = v5; + yield; + }, + ); + assert_static( + #[coroutine] + || { + let v6 = v6; + yield; + }, + ); fn foo(a: &str, b: &str) {} diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index fa2ac7a1b37e8..d69c86c70e291 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -27,7 +27,7 @@ LL | || do_nothing(value) LL | || }); | ||______^- help: try: `if let Ok(value) = x.field { ... }` | |______| - | + | error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:37:5 diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed index 9573fdbcfde33..a18d6319f89db 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.fixed +++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { @@ -10,9 +10,9 @@ fn main() { let y = "x"; x.split(y); - x.split('ß'); - x.split('ℝ'); - x.split('💣'); + x.split("ß"); + x.split("ℝ"); + x.split("💣"); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.split_inclusive('x'); @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices('x'); x.trim_start_matches('x'); x.trim_end_matches('x'); - x.strip_prefix('x'); - x.strip_suffix('x'); x.replace('x', "y"); x.replacen('x', "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split('\\'); x.split('\\'); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs index 8a04480dbc643..b52e6fb2fdfba 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.rs +++ b/src/tools/clippy/tests/ui/single_char_pattern.rs @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices("x"); x.trim_start_matches("x"); x.trim_end_matches("x"); - x.strip_prefix("x"); - x.strip_suffix("x"); x.replace("x", "y"); x.replacen("x", "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split(r#"\"#); x.split(r"\"); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index 5a2ec6c764b18..b2deed23cbd53 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -7,24 +7,6 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:13:13 - | -LL | x.split("ß"); - | ^^^ help: consider using a `char`: `'ß'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:14:13 - | -LL | x.split("ℝ"); - | ^^^ help: consider using a `char`: `'ℝ'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:15:13 - | -LL | x.split("💣"); - | ^^^^ help: consider using a `char`: `'💣'` - error: single-character string constant used as pattern --> tests/ui/single_char_pattern.rs:18:23 | @@ -140,106 +122,94 @@ LL | x.trim_end_matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:37:20 - | -LL | x.strip_prefix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:38:20 - | -LL | x.strip_suffix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:39:15 + --> tests/ui/single_char_pattern.rs:37:15 | LL | x.replace("x", "y"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:40:16 + --> tests/ui/single_char_pattern.rs:38:16 | LL | x.replacen("x", "y", 3); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:42:13 + --> tests/ui/single_char_pattern.rs:40:13 | LL | x.split("\n"); | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:43:13 + --> tests/ui/single_char_pattern.rs:41:13 | LL | x.split("'"); | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:44:13 + --> tests/ui/single_char_pattern.rs:42:13 | LL | x.split("\'"); | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:46:13 + --> tests/ui/single_char_pattern.rs:44:13 | LL | x.split("\""); | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:51:31 + --> tests/ui/single_char_pattern.rs:49:31 | LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:52:19 + --> tests/ui/single_char_pattern.rs:50:19 | LL | x.starts_with("\x03"); // issue #2996 | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:59:13 + --> tests/ui/single_char_pattern.rs:57:13 | LL | x.split(r"a"); | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:60:13 + --> tests/ui/single_char_pattern.rs:58:13 | LL | x.split(r#"a"#); | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:61:13 + --> tests/ui/single_char_pattern.rs:59:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:62:13 + --> tests/ui/single_char_pattern.rs:60:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:63:13 + --> tests/ui/single_char_pattern.rs:61:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:65:13 + --> tests/ui/single_char_pattern.rs:63:13 | LL | x.split(r#"\"#); | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:66:13 + --> tests/ui/single_char_pattern.rs:64:13 | LL | x.split(r"\"); | ^^^^ help: consider using a `char`: `'\\'` -error: aborting due to 40 previous errors +error: aborting due to 35 previous errors diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr index b54309b44d5d8..f12053b1595a1 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr @@ -85,7 +85,7 @@ LL | | ///! b help: use an inner doc comment to document the parent module or crate | LL ~ //! a -LL | +LL | LL ~ //! b | diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr index 23d5dcd3a8dab..aef6c39145263 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr @@ -1,53 +1,53 @@ error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:6:5 | -LL | /// - First String: - | ^^^^ help: consider using four spaces per tab +LL | /// - first one + | ^^^^ help: consider using four spaces per tab | = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 + --> tests/ui/tabs_in_doc_comments.rs:6:13 | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - first one + | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:7:5 | -LL | /// - Second String: - | ^^^^ help: consider using four spaces per tab +LL | /// - second one + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 + --> tests/ui/tabs_in_doc_comments.rs:7:14 | -LL | /// - needs to be inside here - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - second one + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:10:9 | -LL | /// - first one - | ^^^^ help: consider using four spaces per tab +LL | /// - First String: + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 + --> tests/ui/tabs_in_doc_comments.rs:11:9 | -LL | /// - first one - | ^^^^^^^^ help: consider using four spaces per tab +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 + --> tests/ui/tabs_in_doc_comments.rs:14:9 | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab +LL | /// - Second String: + | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 + --> tests/ui/tabs_in_doc_comments.rs:15:9 | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab +LL | /// - needs to be inside here + | ^^^^^^^^ help: consider using four spaces per tab error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed index a6ed59d49c54f..4c9bd0bd8634f 100644 --- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed @@ -1,6 +1,6 @@ #![warn(clippy::thread_local_initializer_can_be_made_const)] -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; fn main() { // lint and suggest const @@ -36,6 +36,37 @@ fn main() { } } +fn issue_12637() { + /// The set methods on LocalKey> and LocalKey> are + /// guaranteed to bypass the thread_local's initialization expression. + /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for + /// forcing the use of set on each thread before it accesses the thread local in any other + /// manner. + thread_local! { + static STATE_12637_PANIC: Cell = panic!(); + } + STATE_12637_PANIC.set(9); + println!("{}", STATE_12637_PANIC.get()); + + thread_local! { + static STATE_12637_TODO: Cell = todo!(); + } + STATE_12637_TODO.set(9); + println!("{}", STATE_12637_TODO.get()); + + thread_local! { + static STATE_12637_UNIMPLEMENTED: Cell = unimplemented!(); + } + STATE_12637_UNIMPLEMENTED.set(9); + println!("{}", STATE_12637_UNIMPLEMENTED.get()); + + thread_local! { + static STATE_12637_UNREACHABLE: Cell = unreachable!(); + } + STATE_12637_UNREACHABLE.set(9); + println!("{}", STATE_12637_UNREACHABLE.get()); +} + #[clippy::msrv = "1.58"] fn f() { thread_local! { diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs index 3f0159c58065c..eb336f0dd1913 100644 --- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs @@ -1,6 +1,6 @@ #![warn(clippy::thread_local_initializer_can_be_made_const)] -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; fn main() { // lint and suggest const @@ -36,6 +36,37 @@ fn main() { } } +fn issue_12637() { + /// The set methods on LocalKey> and LocalKey> are + /// guaranteed to bypass the thread_local's initialization expression. + /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for + /// forcing the use of set on each thread before it accesses the thread local in any other + /// manner. + thread_local! { + static STATE_12637_PANIC: Cell = panic!(); + } + STATE_12637_PANIC.set(9); + println!("{}", STATE_12637_PANIC.get()); + + thread_local! { + static STATE_12637_TODO: Cell = todo!(); + } + STATE_12637_TODO.set(9); + println!("{}", STATE_12637_TODO.get()); + + thread_local! { + static STATE_12637_UNIMPLEMENTED: Cell = unimplemented!(); + } + STATE_12637_UNIMPLEMENTED.set(9); + println!("{}", STATE_12637_UNIMPLEMENTED.get()); + + thread_local! { + static STATE_12637_UNREACHABLE: Cell = unreachable!(); + } + STATE_12637_UNREACHABLE.set(9); + println!("{}", STATE_12637_UNREACHABLE.get()); +} + #[clippy::msrv = "1.58"] fn f() { thread_local! { diff --git a/src/tools/clippy/tests/ui/type_complexity.rs b/src/tools/clippy/tests/ui/type_complexity.rs index b057dc4e89f26..be28ee2da0cd4 100644 --- a/src/tools/clippy/tests/ui/type_complexity.rs +++ b/src/tools/clippy/tests/ui/type_complexity.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![warn(clippy::all)] #![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] #![feature(associated_type_defaults)] diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr index bfbab8647e85c..9e27899e4f904 100644 --- a/src/tools/clippy/tests/ui/type_complexity.stderr +++ b/src/tools/clippy/tests/ui/type_complexity.stderr @@ -1,5 +1,5 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:9:12 + --> tests/ui/type_complexity.rs:7:12 | LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,85 +8,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]` error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:12:12 + --> tests/ui/type_complexity.rs:10:12 | LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:16:8 + --> tests/ui/type_complexity.rs:14:8 | LL | f: Vec>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:20:11 + --> tests/ui/type_complexity.rs:18:11 | LL | struct Ts(Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:24:11 + --> tests/ui/type_complexity.rs:22:11 | LL | Tuple(Vec>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:26:17 + --> tests/ui/type_complexity.rs:24:17 | LL | Struct { f: Vec>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:31:14 + --> tests/ui/type_complexity.rs:29:14 | LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:33:30 + --> tests/ui/type_complexity.rs:31:30 | LL | fn impl_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:38:14 + --> tests/ui/type_complexity.rs:36:14 | LL | const A: Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:40:14 + --> tests/ui/type_complexity.rs:38:14 | LL | type B = Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:42:25 + --> tests/ui/type_complexity.rs:40:25 | LL | fn method(&self, p: Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:44:29 + --> tests/ui/type_complexity.rs:42:29 | LL | fn def_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:57:15 + --> tests/ui/type_complexity.rs:55:15 | LL | fn test1() -> Vec>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:62:14 + --> tests/ui/type_complexity.rs:60:14 | LL | fn test2(_x: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:66:13 + --> tests/ui/type_complexity.rs:64:13 | LL | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs index f6d09834adb17..67e398e604b4b 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs +++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs @@ -19,7 +19,7 @@ where impl NormalTrait for T {} fn main() { - // (currently we don't look deeper than one level into the supertrait hierachy, but we probably + // (currently we don't look deeper than one level into the supertrait hierarchy, but we probably // could) let b: Box = Box::new(1); let _ = b.type_id(); diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 901977da25be4..4d66b728b76df 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -20,7 +20,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ - "y21", "matthiaskrgr", "giraffate", "Centri3", diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index f59245e556cd2..c63edd5bf7098 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -415,7 +415,7 @@ let terms = searchStr.split(" "); let docsLowerCase = lint.docs.toLowerCase(); for (index = 0; index < terms.length; index++) { - // This is more likely and will therefor be checked first + // This is more likely and will therefore be checked first if (docsLowerCase.indexOf(terms[index]) !== -1) { continue; } diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 38c29b91928c7..52beb4c8b3dec 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -21,10 +21,8 @@ regex = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rustfix = "0.8.1" -once_cell = "1.16.0" walkdir = "2" glob = "0.3.0" -lazycell = "1.3.0" anyhow = "1" home = "0.5.5" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index aa69791b3b4b4..afbcc3e92bcb2 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -6,10 +6,10 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; +use std::sync::OnceLock; use crate::util::{add_dylib_path, PathBufExt}; use build_helper::git::GitConfig; -use lazycell::AtomicLazyCell; use serde::de::{Deserialize, Deserializer, Error as _}; use std::collections::{HashMap, HashSet}; use test::{ColorConfig, OutputFormat}; @@ -384,7 +384,7 @@ pub struct Config { /// Only rerun the tests that result has been modified accoring to Git status pub only_modified: bool, - pub target_cfgs: AtomicLazyCell, + pub target_cfgs: OnceLock, pub nocapture: bool, @@ -406,13 +406,7 @@ impl Config { } pub fn target_cfgs(&self) -> &TargetCfgs { - match self.target_cfgs.borrow() { - Some(cfgs) => cfgs, - None => { - let _ = self.target_cfgs.fill(TargetCfgs::new(self)); - self.target_cfgs.borrow().unwrap() - } - } + self.target_cfgs.get_or_init(|| TargetCfgs::new(self)) } pub fn target_cfg(&self) -> &TargetCfg { diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 3231f9fd3a4b9..c11d3da13a8b2 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -6,8 +6,8 @@ use std::io::prelude::*; use std::io::BufReader; use std::path::Path; use std::str::FromStr; +use std::sync::OnceLock; -use once_cell::sync::Lazy; use regex::Regex; use tracing::*; @@ -117,10 +117,11 @@ fn parse_expected( // //~^^^^^ // //[rev1]~ // //[rev1,rev2]~^^ - static RE: Lazy = - Lazy::new(|| Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\||\^*)").unwrap()); + static RE: OnceLock = OnceLock::new(); - let captures = RE.captures(line)?; + let captures = RE + .get_or_init(|| Regex::new(r"//(?:\[(?P[\w\-,]+)])?~(?P\||\^*)").unwrap()) + .captures(line)?; match (test_revision, captures.name("revs")) { // Only error messages that contain our revision between the square brackets apply to us. diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8aafbb3e39926..34e65c7d61fe5 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -5,8 +5,8 @@ use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; use std::process::Command; +use std::sync::OnceLock; -use once_cell::sync::Lazy; use regex::Regex; use tracing::*; @@ -1021,8 +1021,9 @@ fn iter_header( let mut line_number = 0; // Match on error annotations like `//~ERROR`. - static REVISION_MAGIC_COMMENT_RE: Lazy = - Lazy::new(|| Regex::new("//(\\[.*\\])?~.*").unwrap()); + static REVISION_MAGIC_COMMENT_RE: OnceLock = OnceLock::new(); + let revision_magic_comment_re = + REVISION_MAGIC_COMMENT_RE.get_or_init(|| Regex::new("//(\\[.*\\])?~.*").unwrap()); loop { line_number += 1; @@ -1087,7 +1088,7 @@ fn iter_header( }); // Then we try to check for legacy-style candidates, which are not the magic ~ERROR family // error annotations. - } else if !REVISION_MAGIC_COMMENT_RE.is_match(ln) { + } else if !revision_magic_comment_re.is_match(ln) { let Some((_, rest)) = line_directive("//", ln) else { continue; }; diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index db154932d5b54..7bc7e4b868038 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -119,16 +119,6 @@ pub(super) fn handle_needs( condition: config.debugger != Some(Debugger::Lldb) || config.lldb_native_rust, ignore_reason: "ignored on targets without Rust's LLDB", }, - Need { - name: "needs-i686-dlltool", - condition: cache.i686_dlltool, - ignore_reason: "ignored when dlltool for i686 is not present", - }, - Need { - name: "needs-x86_64-dlltool", - condition: cache.x86_64_dlltool, - ignore_reason: "ignored when dlltool for x86_64 is not present", - }, Need { name: "needs-dlltool", condition: cache.dlltool, @@ -218,27 +208,11 @@ pub(super) struct CachedNeedsConditions { profiler_support: bool, xray: bool, rust_lld: bool, - i686_dlltool: bool, - x86_64_dlltool: bool, dlltool: bool, } impl CachedNeedsConditions { pub(super) fn load(config: &Config) -> Self { - let path = std::env::var_os("PATH").expect("missing PATH environment variable"); - let path = std::env::split_paths(&path).collect::>(); - - // On Windows, dlltool.exe is used for all architectures. - #[cfg(windows)] - let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file()); - - // For non-Windows, there are architecture specific dlltool binaries. - #[cfg(not(windows))] - let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()); - #[cfg(not(windows))] - let x86_64_dlltool = - path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()); - let target = &&*config.target; let sanitizers = &config.target_cfg().sanitizers; Self { @@ -278,26 +252,30 @@ impl CachedNeedsConditions { .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(), - #[cfg(windows)] - i686_dlltool: dlltool, - #[cfg(windows)] - x86_64_dlltool: dlltool, - #[cfg(windows)] - dlltool, - - // For non-Windows, there are architecture specific dlltool binaries. - #[cfg(not(windows))] - i686_dlltool, - #[cfg(not(windows))] - x86_64_dlltool, - #[cfg(not(windows))] - dlltool: if config.matches_arch("x86") { - i686_dlltool - } else if config.matches_arch("x86_64") { - x86_64_dlltool - } else { - false - }, + dlltool: find_dlltool(&config), } } } + +fn find_dlltool(config: &Config) -> bool { + let path = std::env::var_os("PATH").expect("missing PATH environment variable"); + let path = std::env::split_paths(&path).collect::>(); + + // dlltool is used ony by GNU based `*-*-windows-gnu` + if !(config.matches_os("windows") && config.matches_env("gnu") && config.matches_abi("")) { + return false; + } + + // On Windows, dlltool.exe is used for all architectures. + // For non-Windows, there are architecture specific dlltool binaries. + let dlltool_found = if cfg!(windows) { + path.iter().any(|dir| dir.join("dlltool.exe").is_file()) + } else if config.matches_arch("i686") { + path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()) + } else if config.matches_arch("x86_64") { + path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()) + } else { + false + }; + dlltool_found +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index c8a8b79921e21..2e45caec46cd6 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -24,13 +24,13 @@ use crate::util::logv; use build_helper::git::{get_git_modified_files, get_git_untracked_files}; use core::panic; use getopts::Options; -use lazycell::AtomicLazyCell; use std::collections::HashSet; use std::ffi::OsString; use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use std::sync::{Arc, OnceLock}; use std::time::SystemTime; use std::{env, vec}; use test::ColorConfig; @@ -39,7 +39,6 @@ use walkdir::WalkDir; use self::header::{make_test_description, EarlyProps}; use crate::header::HeadersCache; -use std::sync::Arc; pub fn parse_config(args: Vec) -> Config { let mut opts = Options::new(); @@ -320,7 +319,7 @@ pub fn parse_config(args: Vec) -> Config { force_rerun: matches.opt_present("force-rerun"), - target_cfgs: AtomicLazyCell::new(), + target_cfgs: OnceLock::new(), nocapture: matches.opt_present("nocapture"), diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index a4235381beb6f..218bea68a218a 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -4,7 +4,7 @@ /// on the number of cores available. /// /// This fixes issue #7772. -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "visionos"))] +#[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] pub unsafe fn raise_fd_limit() { use std::cmp; @@ -50,5 +50,5 @@ pub unsafe fn raise_fd_limit() { } } -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(not(target_vendor = "apple"))] pub unsafe fn raise_fd_limit() {} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1dd639a89188b..0a861d62c3726 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -36,7 +36,6 @@ use std::sync::Arc; use anyhow::Context; use glob::glob; -use once_cell::sync::Lazy; use tracing::*; use crate::extract_gdb_version; @@ -48,6 +47,13 @@ use debugger::DebuggerCommands; #[cfg(test)] mod tests; +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} + const FAKE_SRC_BASE: &str = "fake-test-src-base"; #[cfg(windows)] @@ -765,28 +771,23 @@ impl<'test> TestCx<'test> { // ` 100|` => ` LL|` // ` | 1000|` => ` | LL|` // ` | | 1000|` => ` | | LL|` - static LINE_NUMBER_RE: Lazy = - Lazy::new(|| Regex::new(r"(?m:^)(?(?: \|)*) *[0-9]+\|").unwrap()); - let coverage = LINE_NUMBER_RE.replace_all(&coverage, "${prefix} LL|"); + let coverage = static_regex!(r"(?m:^)(?(?: \|)*) *[0-9]+\|") + .replace_all(&coverage, "${prefix} LL|"); // ` | Branch (1:` => ` | Branch (LL:` // ` | | Branch (10:` => ` | | Branch (LL:` - static BRANCH_LINE_NUMBER_RE: Lazy = - Lazy::new(|| Regex::new(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:").unwrap()); - let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + let coverage = static_regex!(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` - static MCDC_DECISION_LINE_NUMBER_RE: Lazy = Lazy::new(|| { - Regex::new(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:").unwrap() - }); let coverage = - MCDC_DECISION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:${middle}LL:"); + static_regex!(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:${middle}LL:"); // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` - static MCDC_CONDITION_LINE_NUMBER_RE: Lazy = Lazy::new(|| { - Regex::new(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:").unwrap() - }); - let coverage = MCDC_CONDITION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + let coverage = + static_regex!(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); coverage.into_owned() } @@ -2139,6 +2140,7 @@ impl<'test> TestCx<'test> { if !self.props.aux_bins.is_empty() { let aux_bin_dir = self.aux_bin_output_dir_name(); + remove_and_create_dir_all(&aux_dir); remove_and_create_dir_all(&aux_bin_dir); } @@ -3471,13 +3473,12 @@ impl<'test> TestCx<'test> { // the form .-in-., // remove all crate-disambiguators. fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String { - static RE: Lazy = Lazy::new(|| { - Regex::new(r"^[^\.]+(?P\.[[:alnum:]]+)(-in-[^\.]+(?P\.[[:alnum:]]+))?") - .unwrap() - }); - - let captures = - RE.captures(cgu).unwrap_or_else(|| panic!("invalid cgu name encountered: {}", cgu)); + let Some(captures) = + static_regex!(r"^[^\.]+(?P\.[[:alnum:]]+)(-in-[^\.]+(?P\.[[:alnum:]]+))?") + .captures(cgu) + else { + panic!("invalid cgu name encountered: {cgu}"); + }; let mut new_name = cgu.to_owned(); @@ -3824,6 +3825,7 @@ impl<'test> TestCx<'test> { .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) .arg("--extern") .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) + .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) .env("TARGET", &self.config.target) .env("PYTHON", &self.config.python) @@ -4073,18 +4075,16 @@ impl<'test> TestCx<'test> { // 'uploaded "$TEST_BUILD_DIR/, waiting for result"' // is printed to stdout by the client and then captured in the ProcRes, // so it needs to be removed when comparing the run-pass test execution output. - static REMOTE_TEST_RE: Lazy = Lazy::new(|| { - Regex::new( - "^uploaded \"\\$TEST_BUILD_DIR(/[[:alnum:]_\\-.]+)+\", waiting for result\n" - ) - .unwrap() - }); - normalized_stdout = REMOTE_TEST_RE.replace(&normalized_stdout, "").to_string(); + normalized_stdout = static_regex!( + "^uploaded \"\\$TEST_BUILD_DIR(/[[:alnum:]_\\-.]+)+\", waiting for result\n" + ) + .replace(&normalized_stdout, "") + .to_string(); // When there is a panic, the remote-test-client also prints "died due to signal"; // that needs to be removed as well. - static SIGNAL_DIED_RE: Lazy = - Lazy::new(|| Regex::new("^died due to signal [0-9]+\n").unwrap()); - normalized_stdout = SIGNAL_DIED_RE.replace(&normalized_stdout, "").to_string(); + normalized_stdout = static_regex!("^died due to signal [0-9]+\n") + .replace(&normalized_stdout, "") + .to_string(); // FIXME: it would be much nicer if we could just tell the remote-test-client to not // print these things. } @@ -4556,10 +4556,9 @@ impl<'test> TestCx<'test> { // with placeholders as we do not want tests needing updated when compiler source code // changes. // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL - static SRC_DIR_RE: Lazy = - Lazy::new(|| Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?").unwrap()); - - normalized = SRC_DIR_RE.replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned(); + normalized = static_regex!("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?") + .replace_all(&normalized, "SRC_DIR$1:LL:COL") + .into_owned(); normalized = Self::normalize_platform_differences(&normalized); normalized = normalized.replace("\t", "\\t"); // makes tabs visible @@ -4568,34 +4567,29 @@ impl<'test> TestCx<'test> { // since they duplicate actual errors and make the output hard to read. // This mirrors the regex in src/tools/tidy/src/style.rs, please update // both if either are changed. - static ANNOTATION_RE: Lazy = - Lazy::new(|| Regex::new("\\s*//(\\[.*\\])?~.*").unwrap()); - - normalized = ANNOTATION_RE.replace_all(&normalized, "").into_owned(); + normalized = + static_regex!("\\s*//(\\[.*\\])?~.*").replace_all(&normalized, "").into_owned(); // This code normalizes various hashes in v0 symbol mangling that is // emitted in the ui and mir-opt tests. - static V0_CRATE_HASH_PREFIX_RE: Lazy = - Lazy::new(|| Regex::new(r"_R.*?Cs[0-9a-zA-Z]+_").unwrap()); - static V0_CRATE_HASH_RE: Lazy = - Lazy::new(|| Regex::new(r"Cs[0-9a-zA-Z]+_").unwrap()); + let v0_crate_hash_prefix_re = static_regex!(r"_R.*?Cs[0-9a-zA-Z]+_"); + let v0_crate_hash_re = static_regex!(r"Cs[0-9a-zA-Z]+_"); const V0_CRATE_HASH_PLACEHOLDER: &str = r"CsCRATE_HASH_"; - if V0_CRATE_HASH_PREFIX_RE.is_match(&normalized) { + if v0_crate_hash_prefix_re.is_match(&normalized) { // Normalize crate hash normalized = - V0_CRATE_HASH_RE.replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER).into_owned(); + v0_crate_hash_re.replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER).into_owned(); } - static V0_BACK_REF_PREFIX_RE: Lazy = - Lazy::new(|| Regex::new(r"\(_R.*?B[0-9a-zA-Z]_").unwrap()); - static V0_BACK_REF_RE: Lazy = Lazy::new(|| Regex::new(r"B[0-9a-zA-Z]_").unwrap()); + let v0_back_ref_prefix_re = static_regex!(r"\(_R.*?B[0-9a-zA-Z]_"); + let v0_back_ref_re = static_regex!(r"B[0-9a-zA-Z]_"); const V0_BACK_REF_PLACEHOLDER: &str = r"B_"; - if V0_BACK_REF_PREFIX_RE.is_match(&normalized) { + if v0_back_ref_prefix_re.is_match(&normalized) { // Normalize back references (see RFC 2603) normalized = - V0_BACK_REF_RE.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned(); + v0_back_ref_re.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned(); } // AllocId are numbered globally in a compilation session. This can lead to changes @@ -4608,26 +4602,22 @@ impl<'test> TestCx<'test> { let mut seen_allocs = indexmap::IndexSet::new(); // The alloc-id appears in pretty-printed allocations. - static ALLOC_ID_PP_RE: Lazy = Lazy::new(|| { - Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?()?( \([0-9]+ ptr bytes\))?─*╼") - .unwrap() - }); - normalized = ALLOC_ID_PP_RE - .replace_all(&normalized, |caps: &Captures<'_>| { - // Renumber the captured index. - let index = caps.get(2).unwrap().as_str().to_string(); - let (index, _) = seen_allocs.insert_full(index); - let offset = caps.get(3).map_or("", |c| c.as_str()); - let imm = caps.get(4).map_or("", |c| c.as_str()); - // Do not bother keeping it pretty, just make it deterministic. - format!("╾ALLOC{index}{offset}{imm}╼") - }) - .into_owned(); + normalized = static_regex!( + r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?()?( \([0-9]+ ptr bytes\))?─*╼" + ) + .replace_all(&normalized, |caps: &Captures<'_>| { + // Renumber the captured index. + let index = caps.get(2).unwrap().as_str().to_string(); + let (index, _) = seen_allocs.insert_full(index); + let offset = caps.get(3).map_or("", |c| c.as_str()); + let imm = caps.get(4).map_or("", |c| c.as_str()); + // Do not bother keeping it pretty, just make it deterministic. + format!("╾ALLOC{index}{offset}{imm}╼") + }) + .into_owned(); // The alloc-id appears in a sentence. - static ALLOC_ID_RE: Lazy = - Lazy::new(|| Regex::new(r"\balloc([0-9]+)\b").unwrap()); - normalized = ALLOC_ID_RE + normalized = static_regex!(r"\balloc([0-9]+)\b") .replace_all(&normalized, |caps: &Captures<'_>| { let index = caps.get(1).unwrap().as_str().to_string(); let (index, _) = seen_allocs.insert_full(index); @@ -4650,12 +4640,13 @@ impl<'test> TestCx<'test> { /// Replaces backslashes in paths with forward slashes, and replaces CRLF line endings /// with LF. fn normalize_platform_differences(output: &str) -> String { - /// Used to find Windows paths. - /// - /// It's not possible to detect paths in the error messages generally, but this is a - /// decent enough heuristic. - static PATH_BACKSLASH_RE: Lazy = Lazy::new(|| { - Regex::new( + let output = output.replace(r"\\", r"\"); + + // Used to find Windows paths. + // + // It's not possible to detect paths in the error messages generally, but this is a + // decent enough heuristic. + static_regex!( r#"(?x) (?: # Match paths that don't include spaces. @@ -4663,14 +4654,8 @@ impl<'test> TestCx<'test> { | # If the path starts with a well-known root, then allow spaces and no file extension. \$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_'\ ]+)+ - )"#, + )"# ) - .unwrap() - }); - - let output = output.replace(r"\\", r"\"); - - PATH_BACKSLASH_RE .replace_all(&output, |caps: &Captures<'_>| { println!("{}", &caps[0]); caps[0].replace(r"\", "/") diff --git a/src/tools/expand-yaml-anchors/Cargo.toml b/src/tools/expand-yaml-anchors/Cargo.toml deleted file mode 100644 index 9a25b6c1f1c87..0000000000000 --- a/src/tools/expand-yaml-anchors/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "expand-yaml-anchors" -version = "0.1.0" -edition = "2021" - -[dependencies] -yaml-rust = "0.4.3" -yaml-merge-keys = "0.4.0" diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs deleted file mode 100644 index 60651734b9e30..0000000000000 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ /dev/null @@ -1,198 +0,0 @@ -use std::error::Error; -use std::path::{Path, PathBuf}; -use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; - -/// List of files to expand. The first tuple element is the source -/// file, while the second tuple element is the destination file. -#[rustfmt::skip] -static TO_EXPAND: &[(&str, &str)] = &[ - ("src/ci/github-actions/ci.yml", ".github/workflows/ci.yml"), -]; - -/// Name of a special key that will be removed from all the maps in expanded configuration files. -/// This key can then be used to contain shared anchors. -static REMOVE_MAP_KEY: &str = "x--expand-yaml-anchors--remove"; - -/// Message that will be included at the top of all the expanded files. {source} will be replaced -/// with the source filename relative to the base path. -static HEADER_MESSAGE: &str = "\ -############################################################# -# WARNING: automatically generated file, DO NOT CHANGE! # -############################################################# - -# This file was automatically generated by the expand-yaml-anchors tool. The -# source file that generated this one is: -# -# {source} -# -# Once you make changes to that file you need to run: -# -# ./x.py run src/tools/expand-yaml-anchors/ -# -# The CI build will fail if the tool is not run after changes to this file. - -"; - -enum Mode { - Check, - Generate, -} - -struct App { - mode: Mode, - base: PathBuf, -} - -impl App { - fn from_args() -> Result> { - // Parse CLI arguments - let args = std::env::args().skip(1).collect::>(); - let (mode, base) = match args.iter().map(|s| s.as_str()).collect::>().as_slice() { - ["generate", ref base] => (Mode::Generate, PathBuf::from(base)), - ["check", ref base] => (Mode::Check, PathBuf::from(base)), - _ => { - eprintln!("usage: expand-yaml-anchors "); - std::process::exit(1); - } - }; - - Ok(App { mode, base }) - } - - fn run(&self) -> Result<(), Box> { - for (source, dest) in TO_EXPAND { - let source = self.base.join(source); - let dest_path = self.base.join(dest); - - self.expand(&source, &dest_path).with_context(|| match self.mode { - Mode::Generate => format!( - "failed to expand {} into {}", - self.path(&source), - self.path(&dest_path) - ), - Mode::Check => format!( - "{} is not up to date; please run \ - `x.py run src/tools/expand-yaml-anchors`.", - self.path(&dest_path) - ), - })?; - } - Ok(()) - } - - fn expand(&self, source: &Path, dest: &Path) -> Result<(), Box> { - let content = std::fs::read_to_string(source) - .with_context(|| format!("failed to read {}", self.path(source)))?; - - let mut buf = - HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/")); - - let documents = YamlLoader::load_from_str(&content) - .with_context(|| format!("failed to parse {}", self.path(source)))?; - for mut document in documents.into_iter() { - document = yaml_merge_keys::merge_keys(document) - .with_context(|| format!("failed to expand {}", self.path(source)))?; - document = filter_document(document); - - YamlEmitter::new(&mut buf).dump(&document).map_err(|err| WithContext { - context: "failed to serialize the expanded yaml".into(), - source: Box::new(err), - })?; - buf.push('\n'); - } - - match self.mode { - Mode::Check => { - let old = std::fs::read_to_string(dest) - .with_context(|| format!("failed to read {}", self.path(dest)))?; - if old != buf { - return Err(Box::new(StrError(format!( - "{} and {} are different", - self.path(source), - self.path(dest), - )))); - } - } - Mode::Generate => { - std::fs::write(dest, buf.as_bytes()) - .with_context(|| format!("failed to write to {}", self.path(dest)))?; - } - } - Ok(()) - } - - fn path<'a>(&self, path: &'a Path) -> impl std::fmt::Display + 'a { - path.strip_prefix(&self.base).unwrap_or(path).display() - } -} - -fn filter_document(document: Yaml) -> Yaml { - match document { - Yaml::Hash(map) => Yaml::Hash( - map.into_iter() - .filter(|(key, _)| { - if let Yaml::String(string) = &key { string != REMOVE_MAP_KEY } else { true } - }) - .map(|(key, value)| (filter_document(key), filter_document(value))) - .collect(), - ), - Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()), - other => other, - } -} - -fn main() { - if let Err(err) = App::from_args().and_then(|app| app.run()) { - eprintln!("error: {}", err); - - let mut source = err.as_ref() as &dyn Error; - while let Some(err) = source.source() { - eprintln!("caused by: {}", err); - source = err; - } - - std::process::exit(1); - } -} - -#[derive(Debug)] -struct StrError(String); - -impl Error for StrError {} - -impl std::fmt::Display for StrError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } -} - -#[derive(Debug)] -struct WithContext { - context: String, - source: Box, -} - -impl std::fmt::Display for WithContext { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.context) - } -} - -impl Error for WithContext { - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(self.source.as_ref()) - } -} - -pub(crate) trait ResultExt { - fn with_context String>(self, f: F) -> Result>; -} - -impl>> ResultExt for Result { - fn with_context String>(self, f: F) -> Result> { - match self { - Ok(ok) => Ok(ok), - Err(err) => Err(WithContext { source: err.into(), context: f() }.into()), - } - } -} diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index 6326a9b1e79c3..e1eb6d0566513 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -10,4 +10,3 @@ regex = "1.4" shlex = "1.0" serde_json = "1.0" fs-err = "2.5.0" -once_cell = "1.0" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index e3d05ec83159d..688b403bf0e0a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,8 +1,8 @@ use jsonpath_lib::select; -use once_cell::sync::Lazy; use regex::{Regex, RegexBuilder}; use serde_json::Value; use std::borrow::Cow; +use std::sync::OnceLock; use std::{env, fmt, fs}; mod cache; @@ -95,7 +95,8 @@ impl fmt::Display for CommandKind { } } -static LINE_PATTERN: Lazy = Lazy::new(|| { +static LINE_PATTERN: OnceLock = OnceLock::new(); +fn line_pattern() -> Regex { RegexBuilder::new( r#" \s(?P!?)@(?P!?) @@ -107,7 +108,7 @@ static LINE_PATTERN: Lazy = Lazy::new(|| { .unicode(true) .build() .unwrap() -}); +} fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) @@ -123,7 +124,7 @@ fn get_commands(template: &str) -> Result, ()> { for (lineno, line) in file.split('\n').enumerate() { let lineno = lineno + 1; - let cap = match LINE_PATTERN.captures(line) { + let cap = match LINE_PATTERN.get_or_init(line_pattern).captures(line) { Some(c) => c, None => continue, }; diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 318a69ab8359e..05049aabc7d9c 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -9,5 +9,4 @@ path = "main.rs" [dependencies] regex = "1" -once_cell = "1" html5ever = "0.26.0" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index f49c6e79f13c5..32f935de73025 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -18,8 +18,6 @@ use html5ever::tendril::ByteTendril; use html5ever::tokenizer::{ BufferQueue, TagToken, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts, }; -use once_cell::sync::Lazy; -use regex::Regex; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::env; @@ -69,8 +67,12 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ ]; -static BROKEN_INTRA_DOC_LINK: Lazy = - Lazy::new(|| Regex::new(r#"\[(.*)\]"#).unwrap()); +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} macro_rules! t { ($e:expr) => { @@ -373,7 +375,7 @@ impl Checker { // Search for intra-doc links that rustdoc didn't warn about // NOTE: only looks at one line at a time; in practice this should find most links for (i, line) in source.lines().enumerate() { - for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { + for broken_link in static_regex!(r#"\[(.*)\]"#).captures_iter(line) { if is_intra_doc_exception(file, &broken_link[1]) { report.intra_doc_exceptions += 1; } else { diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 0c39f2fa6010f..73f5738469ed1 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -20,6 +20,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ "refining-impl-trait", "Detects refinement of `impl Trait` return types by trait implementations", ), + ( + "keyword-idents", + "Lints that detect identifiers which will be come keywords in later editions", + ), ]; type LintGroups = BTreeMap>; diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index aca780e33f0ea..22ab576b07762 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -25,6 +25,7 @@ static RENAMES: &[(Level, &[(&str, &str)])] = &[ ("elided-lifetime-in-path", "elided-lifetimes-in-paths"), ("async-idents", "keyword-idents"), ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"), + ("keyword-idents", "keyword-idents-2018"), ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"), ], ), diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index b0dab9f509d4a..0af334a654b40 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: env: HOST_TARGET: ${{ matrix.host_target }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Show Rust version (stable toolchain) run: | @@ -57,12 +57,12 @@ jobs: ~/.cargo/bin ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }} - restore-keys: cargo-${{ runner.os }}-reset20240331 + key: cargo-${{ runner.os }}-reset20240425-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-${{ runner.os }}-reset20240425 - - name: Install rustup-toolchain-install-master + - name: Install tools if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: cargo install -f rustup-toolchain-install-master + run: cargo install -f rustup-toolchain-install-master hyperfine - name: Install miri toolchain run: | @@ -85,7 +85,7 @@ jobs: name: style checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # This is exactly duplicated from above. GHA is pretty terrible when it comes # to avoiding code duplication. @@ -165,7 +165,7 @@ jobs: name: cronjob failure notification runs-on: ubuntu-latest needs: [build, style] - if: github.event_name == 'schedule' && (failure() || cancelled()) + if: github.event_name == 'schedule' && failure() steps: # Send a Zulip notification - name: Install zulip-send @@ -191,7 +191,7 @@ jobs: The Miri Cronjobs Bot' # Attempt to auto-sync with rustc - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 256 # get a bit more of the history - name: install josh-proxy diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 4fb479e1c543b..293b937a5e52b 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -37,6 +37,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "annotate-snippets" version = "0.9.2" @@ -106,6 +121,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "camino" version = "1.1.6" @@ -150,6 +171,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.3", +] + [[package]] name = "cipher" version = "0.4.4" @@ -216,6 +249,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -260,6 +299,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -319,6 +379,29 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "indenter" version = "0.3.3" @@ -372,6 +455,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -419,6 +511,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.4.2", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -484,8 +586,10 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "chrono", "colored", "ctrlc", + "directories", "getrandom", "jemalloc-sys", "lazy_static", @@ -512,6 +616,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -533,6 +646,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "owo-colors" version = "3.5.0" @@ -665,6 +784,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.3" @@ -964,6 +1094,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + [[package]] name = "winapi" version = "0.3.9" @@ -986,6 +1170,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.3", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 9d24d3c6f4779..ac8b4b37e9200 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -24,6 +24,8 @@ smallvec = "1.7" aes = { version = "0.8.3", features = ["hazmat"] } measureme = "11" ctrlc = "3.2.5" +chrono = { version = "0.4.38", default-features = false, features = ["clock"] } +directories = "5" # Copied from `compiler/rustc/Cargo.toml`. # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't @@ -44,7 +46,6 @@ colored = "2" ui_test = "0.21.1" rustc_version = "0.4" regex = "1.5.5" -lazy_static = "1.4.0" tempfile = "3" [package.metadata.rust-analyzer] diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 4254b9bb67dba..ef01ca25fb0b4 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -321,6 +321,10 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. Execution will still be deterministic if the value of forwarded variables stays the same. Has no effect if `-Zmiri-disable-isolation` is set. +* `-Zmiri-env-set==` sets the `var` environment variable to `value` in the interpreted program. + It can be used to pass environment variables without needing to alter the host environment. It can + be used multiple times to set several variables. If `-Zmiri-disable-isolation` or `-Zmiri-env-forward` + is set, values set with this option will have priority over values from the host environment. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-isolation-error=` configures Miri's response to operations @@ -560,7 +564,8 @@ used according to their aliasing restrictions. ## Bugs found by Miri -Miri has already found a number of bugs in the Rust standard library and beyond, which we collect here. +Miri has already found a number of bugs in the Rust standard library and beyond, some of which we collect here. +If Miri helped you find a subtle UB bug in your code, we'd appreciate a PR adding it to the list! Definite bugs found: @@ -595,6 +600,7 @@ Definite bugs found: * [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460) * [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138) * [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084)) +* [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index f8ba612750ee9..c1ffb80783ef6 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -78,8 +78,8 @@ function run_tests { done fi if [ -n "${TEST_BENCH-}" ]; then - # Check that the benchmarks build and run, but without actually benchmarking. - time HYPERFINE="'$BASH' -c" ./miri bench + # Check that the benchmarks build and run, but only once. + time HYPERFINE="hyperfine -w0 -r1" ./miri bench fi ## test-cargo-miri @@ -128,16 +128,18 @@ function run_tests_minimal { ## Main Testing Logic ## # In particular, fully cover all tier 1 targets. +# We also want to run the many-seeds tests on all tier 1 targets. case $HOST_TARGET in x86_64-unknown-linux-gnu) # Host GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests - MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests - MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests + # With reduced many-seed count to avoid spending too much time on that. + # (All OSes are run with 64 seeds at least once though via the macOS runner.) + MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests # Extra tier 2 MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests @@ -155,13 +157,15 @@ case $HOST_TARGET in # Host (tier 2) GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests + MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests + MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture ;; i686-pc-windows-msvc) # Host - # Only smoke-test `many-seeds`; 64 runs take 15min here! + # Only smoke-test `many-seeds`; 64 runs of just the scoped-thread-leak test take 15min here! + # See . GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, diff --git a/src/tools/miri/clippy.toml b/src/tools/miri/clippy.toml new file mode 100644 index 0000000000000..284e18a45a30e --- /dev/null +++ b/src/tools/miri/clippy.toml @@ -0,0 +1 @@ +arithmetic-side-effects-allowed = ["rustc_target::abi::Size"] diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index aaa788d58462d..79d0b13600d4f 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -8,7 +8,9 @@ version = "0.1.0" default-run = "miri-script" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +# We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root. +# This is needed to make this package build on stable when the parent package uses unstable cargo features. [dependencies] which = "4.4" diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index a60acf44a401f..a45ecda15c4c0 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c8d19a92aa9022eb690899cf6d54fd23cb6877e5 +6acb9e75ebc936df737381a9d0b7a7bccd6f0b2f diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index db2cd01ce0bf6..44201cb89ae79 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -1,4 +1,3 @@ -#![feature(generic_nonzero)] #![feature(rustc_private, stmt_expr_attributes)] #![allow( clippy::manual_range_contains, @@ -507,6 +506,11 @@ fn main() { ); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") { + let Some((name, value)) = param.split_once('=') else { + show_error!("-Zmiri-env-set requires an argument of the form ="); + }; + miri_config.set_env_vars.insert(name.to_owned(), value.to_owned()); } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") { let ids: Vec = parse_comma_list(param).unwrap_or_else(|err| { show_error!("-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {err}") diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index bebd14d2f1e71..55ff09c53fede 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -248,7 +248,7 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache")] fn find_granting_cache(&mut self, access: AccessKind, tag: BorTag) -> Option { // This looks like a common-sense optimization; we're going to do a linear search of the - // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule + // cache or the borrow stack to scan the shorter of the two. This optimization is minuscule // and this check actually ensures we do not access an invalid cache. // When a stack is created and when items are removed from the top of the borrow stack, we // need some valid value to populate the cache. In both cases, we try to use the bottom diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 2281609a049d4..f2bec972b18b2 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -847,6 +847,7 @@ impl VClockAlloc { kind: MemoryKind, current_span: Span, ) -> VClockAlloc { + // Determine the thread that did the allocation, and when it did it. let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( @@ -858,13 +859,13 @@ impl VClockAlloc { | MiriMemoryKind::Mmap, ) | MemoryKind::Stack => { - let (alloc_index, clocks) = global.current_thread_state(thread_mgr); + let (alloc_index, clocks) = global.active_thread_state(thread_mgr); let mut alloc_timestamp = clocks.clock[alloc_index]; alloc_timestamp.span = current_span; (alloc_timestamp, alloc_index) } // Other global memory should trace races but be allocated at the 0 timestamp - // (conceptually they are allocated before everything). + // (conceptually they are allocated on the main thread before everything). MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine @@ -872,7 +873,8 @@ impl VClockAlloc { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) - | MemoryKind::CallerLocation => (VTimestamp::ZERO, VectorIdx::MAX_INDEX), + | MemoryKind::CallerLocation => + (VTimestamp::ZERO, global.thread_index(ThreadId::MAIN_THREAD)), }; VClockAlloc { alloc_ranges: RefCell::new(RangeMap::new( @@ -930,7 +932,7 @@ impl VClockAlloc { ptr_dbg: Pointer, ty: Option>, ) -> InterpResult<'tcx> { - let (current_index, current_clocks) = global.current_thread_state(thread_mgr); + let (active_index, active_clocks) = global.active_thread_state(thread_mgr); let mut other_size = None; // if `Some`, this was a size-mismatch race let write_clock; let (other_access, other_thread, other_clock) = @@ -939,30 +941,30 @@ impl VClockAlloc { // we are reporting races between two non-atomic reads. if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && - let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) { (AccessType::AtomicStore, idx, &atomic.write_vector) } else if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && - let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + let Some(idx) = Self::find_gt_index(&atomic.read_vector, &active_clocks.clock) { (AccessType::AtomicLoad, idx, &atomic.read_vector) // Then check races with non-atomic writes/reads. - } else if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] { + } else if mem_clocks.write.1 > active_clocks.clock[mem_clocks.write.0] { write_clock = mem_clocks.write(); (AccessType::NaWrite(mem_clocks.write_type), mem_clocks.write.0, &write_clock) - } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, ¤t_clocks.clock) { + } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &active_clocks.clock) { (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read) // Finally, mixed-size races. } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { // This is only a race if we are not synchronized with all atomic accesses, so find // the one we are not synchronized with. other_size = Some(atomic.size); - if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) { (AccessType::AtomicStore, idx, &atomic.write_vector) } else if let Some(idx) = - Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + Self::find_gt_index(&atomic.read_vector, &active_clocks.clock) { (AccessType::AtomicLoad, idx, &atomic.read_vector) } else { @@ -975,7 +977,7 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions. - let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); + let active_thread_info = global.print_thread_metadata(thread_mgr, active_index); let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); let involves_non_atomic = !access.is_atomic() || !other_access.is_atomic(); @@ -1003,8 +1005,8 @@ impl VClockAlloc { }, op2: RacingOp { action: access.description(ty, other_size.map(|_| access_size)), - thread_info: current_thread_info, - span: current_clocks.clock.as_slice()[current_index.index()].span_data(), + thread_info: active_thread_info, + span: active_clocks.clock.as_slice()[active_index.index()].span_data(), }, }))? } @@ -1026,7 +1028,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_ref().unwrap(); if global.race_detecting() { - let (index, mut thread_clocks) = global.current_thread_state_mut(&machine.threads); + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (mem_clocks_range, mem_clocks) in alloc_ranges.iter_mut(access_range.start, access_range.size) @@ -1069,7 +1071,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_mut().unwrap(); if global.race_detecting() { - let (index, mut thread_clocks) = global.current_thread_state_mut(&machine.threads); + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); for (mem_clocks_range, mem_clocks) in self.alloc_ranges.get_mut().iter_mut(access_range.start, access_range.size) { @@ -1454,7 +1456,7 @@ impl GlobalState { // Setup the main-thread since it is not explicitly created: // uses vector index and thread-id 0. let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); - global_state.vector_info.get_mut().push(ThreadId::new(0)); + global_state.vector_info.get_mut().push(ThreadId::MAIN_THREAD); global_state .thread_info .get_mut() @@ -1518,7 +1520,7 @@ impl GlobalState { thread: ThreadId, current_span: Span, ) { - let current_index = self.current_index(thread_mgr); + let current_index = self.active_thread_index(thread_mgr); // Enable multi-threaded execution, there are now at least two threads // so data-races are now possible. @@ -1642,7 +1644,7 @@ impl GlobalState { /// `thread_joined`. #[inline] pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>, current_span: Span) { - let current_index = self.current_index(thread_mgr); + let current_index = self.active_thread_index(thread_mgr); // Increment the clock to a unique termination timestamp. let vector_clocks = self.vector_clocks.get_mut(); @@ -1680,9 +1682,9 @@ impl GlobalState { op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, clocks) = self.current_thread_state_mut(thread_mgr); + let (index, clocks) = self.active_thread_state_mut(thread_mgr); if op(index, clocks)? { - let (_, mut clocks) = self.current_thread_state_mut(thread_mgr); + let (_, mut clocks) = self.active_thread_state_mut(thread_mgr); clocks.increment_clock(index, current_span); } } @@ -1725,13 +1727,15 @@ impl GlobalState { Ref::map(clocks, |c| &c.clock) } + fn thread_index(&self, thread: ThreadId) -> VectorIdx { + self.thread_info.borrow()[thread].vector_index.expect("thread has no assigned vector") + } + /// Load the vector index used by the given thread as well as the set of vector clocks /// used by the thread. #[inline] fn thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread] - .vector_index - .expect("Loading thread state for thread with no assigned vector"); + let index = self.thread_index(thread); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); (index, clocks) @@ -1741,9 +1745,7 @@ impl GlobalState { /// used by the thread. #[inline] fn thread_state(&self, thread: ThreadId) -> (VectorIdx, Ref<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread] - .vector_index - .expect("Loading thread state for thread with no assigned vector"); + let index = self.thread_index(thread); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); (index, clocks) @@ -1752,7 +1754,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub(super) fn current_thread_state( + pub(super) fn active_thread_state( &self, thread_mgr: &ThreadManager<'_, '_>, ) -> (VectorIdx, Ref<'_, ThreadClockSet>) { @@ -1762,7 +1764,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub(super) fn current_thread_state_mut( + pub(super) fn active_thread_state_mut( &self, thread_mgr: &ThreadManager<'_, '_>, ) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { @@ -1772,22 +1774,20 @@ impl GlobalState { /// Return the current thread, should be the same /// as the data-race active thread. #[inline] - fn current_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { + fn active_thread_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { let active_thread_id = thread_mgr.get_active_thread_id(); - self.thread_info.borrow()[active_thread_id] - .vector_index - .expect("active thread has no assigned vector") + self.thread_index(active_thread_id) } // SC ATOMIC STORE rule in the paper. pub(super) fn sc_write(&self, thread_mgr: &ThreadManager<'_, '_>) { - let (index, clocks) = self.current_thread_state(thread_mgr); + let (index, clocks) = self.active_thread_state(thread_mgr); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. pub(super) fn sc_read(&self, thread_mgr: &ThreadManager<'_, '_>) { - let (.., mut clocks) = self.current_thread_state_mut(thread_mgr); + let (.., mut clocks) = self.active_thread_state_mut(thread_mgr); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 2fabd39a74455..0116bd0281adc 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -57,6 +57,8 @@ impl ThreadId { pub fn to_u32(self) -> u32 { self.0 } + + pub const MAIN_THREAD: ThreadId = ThreadId(0); } impl Idx for ThreadId { @@ -401,7 +403,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { // Create the main thread and add it to the list of threads. threads.push(Thread::new(Some("main"), None)); Self { - active_thread: ThreadId::new(0), + active_thread: ThreadId::MAIN_THREAD, threads, sync: SynchronizationState::default(), thread_local_alloc_ids: Default::default(), @@ -416,10 +418,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { ecx: &mut MiriInterpCx<'mir, 'tcx>, on_main_stack_empty: StackEmptyCallback<'mir, 'tcx>, ) { - ecx.machine.threads.threads[ThreadId::new(0)].on_stack_empty = Some(on_main_stack_empty); + ecx.machine.threads.threads[ThreadId::MAIN_THREAD].on_stack_empty = + Some(on_main_stack_empty); if ecx.tcx.sess.target.os.as_ref() != "windows" { // The main thread can *not* be joined on except on windows. - ecx.machine.threads.threads[ThreadId::new(0)].join_status = ThreadJoinStatus::Detached; + ecx.machine.threads.threads[ThreadId::MAIN_THREAD].join_status = + ThreadJoinStatus::Detached; } } diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 2cd3d031b1edd..c3496bc1a0c8a 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -13,15 +13,13 @@ use super::data_race::NaReadType; /// but in some cases one vector index may be shared with /// multiple thread ids if it's safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct VectorIdx(u32); +pub(super) struct VectorIdx(u32); impl VectorIdx { #[inline(always)] - pub fn to_u32(self) -> u32 { + fn to_u32(self) -> u32 { self.0 } - - pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); } impl Idx for VectorIdx { @@ -51,7 +49,7 @@ const SMALL_VECTOR: usize = 4; /// a 32-bit unsigned integer which is the actual timestamp, and a `Span` /// so that diagnostics can report what code was responsible for an operation. #[derive(Clone, Copy, Debug)] -pub struct VTimestamp { +pub(super) struct VTimestamp { /// The lowest bit indicates read type, the rest is the time. /// `1` indicates a retag read, `0` a regular read. time_and_read_type: u32, @@ -87,7 +85,7 @@ impl VTimestamp { } #[inline] - pub fn read_type(&self) -> NaReadType { + pub(super) fn read_type(&self) -> NaReadType { if self.time_and_read_type & 1 == 0 { NaReadType::Read } else { NaReadType::Retag } } @@ -97,7 +95,7 @@ impl VTimestamp { } #[inline] - pub fn span_data(&self) -> SpanData { + pub(super) fn span_data(&self) -> SpanData { self.span.data() } } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 9ebb64afd3596..574962c48d43e 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -270,7 +270,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { ) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); store_elem.load_impl(index, &clocks, is_seqcst); } } @@ -289,7 +289,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let (store_elem, recency) = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it - let (.., clocks) = global.current_thread_state(thread_mgr); + let (.., clocks) = global.active_thread_state(thread_mgr); // Load from a valid entry in the store buffer self.fetch_store(is_seqcst, &clocks, &mut *rng) }; @@ -300,7 +300,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks, is_seqcst); Ok((loaded, recency)) } @@ -312,7 +312,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, ) -> InterpResult<'tcx> { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); self.store_impl(val, index, &clocks.clock, is_seqcst); Ok(()) @@ -520,7 +520,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: validate, )?; if global.track_outdated_loads && recency == LoadRecency::Outdated { - this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad); + this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad { + ptr: place.ptr(), + }); } return Ok(loaded); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 0c0ac4c6036d9..9fa786332e3cd 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -125,7 +125,9 @@ pub enum NonHaltingDiagnostic { Int2Ptr { details: bool, }, - WeakMemoryOutdatedLoad, + WeakMemoryOutdatedLoad { + ptr: Pointer>, + }, } /// Level of Miri specific diagnostics @@ -583,7 +585,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { | AccessedAlloc(..) | FreedAlloc(..) | ProgressReport { .. } - | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note), + | WeakMemoryOutdatedLoad { .. } => + ("tracking was triggered".to_string(), DiagLevel::Note), }; let msg = match &e { @@ -610,8 +613,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), - WeakMemoryOutdatedLoad => - format!("weak memory emulation: outdated value returned from load"), + WeakMemoryOutdatedLoad { ptr } => + format!("weak memory emulation: outdated value returned from load at {ptr}"), }; let notes = match &e { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 45dadb50f4b26..2242768a56827 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -9,7 +9,7 @@ use std::thread; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ @@ -100,6 +100,8 @@ pub struct MiriConfig { pub ignore_leaks: bool, /// Environment variables that should always be forwarded from the host. pub forwarded_env_vars: Vec, + /// Additional environment variables that should be set in the interpreted program. + pub set_env_vars: FxHashMap, /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). @@ -167,6 +169,7 @@ impl Default for MiriConfig { isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, forwarded_env_vars: vec![], + set_env_vars: FxHashMap::default(), args: vec![], seed: None, tracked_pointer_tags: FxHashSet::default(), @@ -383,10 +386,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx.fn_ptr(FnVal::Instance(entry_instance)); - // Inlining of `DEFAULT` from - // https://github.com/rust-lang/rust/blob/master/compiler/rustc_session/src/config/sigpipe.rs. // Always using DEFAULT is okay since we don't support signals in Miri anyway. - let sigpipe = 2; + // (This means we are effectively ignoring `#[unix_sigpipe]`.) + let sigpipe = rustc_session::config::sigpipe::DEFAULT; ecx.call_function( start_instance, diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2e19c9ff71356..f47c84842b17f 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -2,7 +2,6 @@ #![feature(cell_update)] #![feature(const_option)] #![feature(float_gamma)] -#![feature(generic_nonzero)] #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] @@ -13,7 +12,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(trait_upcasting)] -#![feature(absolute_path)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -91,8 +89,10 @@ mod shims; // Establish a "crate-wide prelude": we often import `crate::*`. // Make all those symbols available in the same place as our own. +#[doc(no_inline)] pub use rustc_const_eval::interpret::*; // Resolve ambiguity. +#[doc(no_inline)] pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index cbe70cbffee55..4dacb6db8da94 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -31,7 +31,7 @@ use rustc_target::spec::abi::Abi; use crate::{ concurrency::{data_race, weak_memory}, - shims::unix::FdTable, + shims::unix, *, }; @@ -380,7 +380,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit); let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); Ok(Self { - unit: layout_cx.layout_of(Ty::new_unit(tcx))?, + unit: layout_cx.layout_of(tcx.types.unit)?, i8: layout_cx.layout_of(tcx.types.i8)?, i16: layout_cx.layout_of(tcx.types.i16)?, i32: layout_cx.layout_of(tcx.types.i32)?, @@ -439,8 +439,7 @@ pub struct MiriMachine<'mir, 'tcx> { /// Ptr-int-cast module global data. pub alloc_addresses: alloc_addresses::GlobalState, - /// Environment variables set by `setenv`. - /// Miri does not expose env vars from the host to the emulated program. + /// Environment variables. pub(crate) env_vars: EnvVars<'tcx>, /// Return place of the main function. @@ -465,9 +464,9 @@ pub struct MiriMachine<'mir, 'tcx> { pub(crate) validate: bool, /// The table of file descriptors. - pub(crate) fds: shims::unix::FdTable, + pub(crate) fds: unix::FdTable, /// The table of directory descriptors. - pub(crate) dirs: shims::unix::DirTable, + pub(crate) dirs: unix::DirTable, /// This machine's monotone clock. pub(crate) clock: Clock, @@ -642,7 +641,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - fds: FdTable::new(config.mute_stdout_stderr), + fds: unix::FdTable::new(config.mute_stdout_stderr), dirs: Default::default(), layouts, threads: ThreadManager::default(), diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index abfa7143a73f6..294ad50c33f29 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -2,7 +2,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; -use rustc_span::{BytePos, Loc, Symbol}; +use rustc_span::{hygiene, BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} @@ -45,12 +45,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { - let mut span = frame.current_span(); - // Match the behavior of runtime backtrace spans - // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. - if span.from_expansion() && !tcx.sess.opts.unstable_opts.debug_macros { - span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) - } + // Match behavior of debuginfo (`FunctionCx::adjusted_span_and_dbg_scope`). + let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body.span); data.push((frame.instance, span.lo())); } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 1779189c9cecc..fc0160fdf2117 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -1,33 +1,24 @@ -use std::env; -use std::ffi::{OsStr, OsString}; -use std::io::ErrorKind; -use std::mem; +use std::ffi::OsString; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::Ty; -use rustc_target::abi::Size; use crate::*; -use helpers::windows_check_buffer_size; +use shims::{unix::UnixEnvVars, windows::WindowsEnvVars}; #[derive(Default)] -pub struct EnvVars<'tcx> { - /// Stores pointers to the environment variables. These variables must be stored as - /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>>, - - /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - pub(crate) environ: Option>, +pub enum EnvVars<'tcx> { + #[default] + Uninit, + Unix(UnixEnvVars<'tcx>), + Windows(WindowsEnvVars), } impl VisitProvenance for EnvVars<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let EnvVars { map, environ } = self; - - environ.visit_provenance(visit); - for ptr in map.values() { - ptr.visit_provenance(visit); + match self { + EnvVars::Uninit => {} + EnvVars::Unix(env) => env.visit_provenance(visit), + EnvVars::Windows(env) => env.visit_provenance(visit), } } } @@ -39,452 +30,73 @@ impl<'tcx> EnvVars<'tcx> { ) -> InterpResult<'tcx> { // Initialize the `env_vars` map. // Skip the loop entirely if we don't want to forward anything. + let mut env_vars = FxHashMap::default(); if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in &config.env { let forward = ecx.machine.communicate() || config.forwarded_env_vars.iter().any(|v| **v == *name); if forward { - let var_ptr = match ecx.tcx.sess.target.os.as_ref() { - _ if ecx.target_os_is_unix() => - alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, - "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => - throw_unsup_format!( - "environment support for target OS `{}` not yet available", - unsupported - ), - }; - ecx.machine.env_vars.map.insert(name.clone(), var_ptr); + env_vars.insert(OsString::from(name), OsString::from(value)); } } } - // Initialize the `environ` pointer when needed. - if ecx.target_os_is_unix() { - // This is memory backing an extern static, hence `ExternStatic`, not `Env`. - let layout = ecx.machine.layouts.mut_raw_ptr; - let place = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - ecx.write_null(&place)?; - ecx.machine.env_vars.environ = Some(place); - ecx.update_environ()?; + for (name, value) in &config.set_env_vars { + env_vars.insert(OsString::from(name), OsString::from(value)); } + + let env_vars = if ecx.target_os_is_unix() { + EnvVars::Unix(UnixEnvVars::new(ecx, env_vars)?) + } else if ecx.tcx.sess.target.os == "windows" { + EnvVars::Windows(WindowsEnvVars::new(ecx, env_vars)?) + } else { + // Used e.g. for wasi + EnvVars::Uninit + }; + ecx.machine.env_vars = env_vars; + Ok(()) } pub(crate) fn cleanup<'mir>( ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, ) -> InterpResult<'tcx> { - // Deallocate individual env vars. - let env_vars = mem::take(&mut ecx.machine.env_vars.map); - for (_name, ptr) in env_vars { - ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?; - } - // Deallocate environ var list. - if ecx.target_os_is_unix() { - let environ = ecx.machine.env_vars.environ.as_ref().unwrap(); - let old_vars_ptr = ecx.read_pointer(environ)?; - ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + let this = ecx.eval_context_mut(); + match this.machine.env_vars { + EnvVars::Unix(_) => UnixEnvVars::cleanup(this), + EnvVars::Windows(_) => Ok(()), // no cleanup needed + EnvVars::Uninit => Ok(()), } - Ok(()) - } -} - -fn alloc_env_var_as_c_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) -} - -fn alloc_env_var_as_wide_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn getenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("getenv"); - - let name_ptr = this.read_pointer(name_op)?; - let name = this.read_os_str_from_c_str(name_ptr)?; - this.read_environ()?; - Ok(match this.machine.env_vars.map.get(name) { - Some(var_ptr) => { - // The offset is used to strip the "{name}=" part of the string. - var_ptr.offset( - Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), - this, - )? - } - None => Pointer::null(), - }) } - #[allow(non_snake_case)] - fn GetEnvironmentVariableW( - &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - buf_op: &OpTy<'tcx, Provenance>, // LPWSTR - size_op: &OpTy<'tcx, Provenance>, // DWORD - ) -> InterpResult<'tcx, Scalar> { - // ^ Returns DWORD (u32 on Windows) - - let this = self.eval_context_mut(); - this.assert_target_os("windows", "GetEnvironmentVariableW"); - - let name_ptr = this.read_pointer(name_op)?; - let name = this.read_os_str_from_wide_str(name_ptr)?; - Ok(match this.machine.env_vars.map.get(&name) { - Some(&var_ptr) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error - // The offset is used to strip the "{name}=" part of the string. - #[rustfmt::skip] - let name_offset_bytes = u64::try_from(name.len()).unwrap() - .checked_add(1).unwrap() - .checked_mul(2).unwrap(); - let var_ptr = var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?; - let var = this.read_os_str_from_wide_str(var_ptr)?; - - let buf_ptr = this.read_pointer(buf_op)?; - // `buf_size` represents the size in characters. - let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - Scalar::from_u32(windows_check_buffer_size( - this.write_os_str_to_wide_str( - &var, buf_ptr, buf_size, /*truncate*/ false, - )?, - )) - } - None => { - let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND"); - this.set_last_error(envvar_not_found)?; - Scalar::from_u32(0) // return zero upon failure - } - }) - } - - #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { - let this = self.eval_context_mut(); - this.assert_target_os("windows", "GetEnvironmentStringsW"); - - // Info on layout of environment blocks in Windows: - // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables - let mut env_vars = std::ffi::OsString::new(); - for &item in this.machine.env_vars.map.values() { - let env_var = this.read_os_str_from_wide_str(item)?; - env_vars.push(env_var); - env_vars.push("\0"); + pub(crate) fn unix(&self) -> &UnixEnvVars<'tcx> { + match self { + EnvVars::Unix(env) => env, + _ => unreachable!(), } - // Allocate environment block & Store environment variables to environment block. - // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - let envblock_ptr = - this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?; - // If the function succeeds, the return value is a pointer to the environment block of the current process. - Ok(envblock_ptr) - } - - #[allow(non_snake_case)] - fn FreeEnvironmentStringsW( - &mut self, - env_block_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - this.assert_target_os("windows", "FreeEnvironmentStringsW"); - - let env_block_ptr = this.read_pointer(env_block_op)?; - let result = this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into()); - // If the function succeeds, the return value is nonzero. - Ok(Scalar::from_i32(i32::from(result.is_ok()))) } - fn setenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - value_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("setenv"); - - let name_ptr = this.read_pointer(name_op)?; - let value_ptr = this.read_pointer(value_op)?; - - let mut new = None; - if !this.ptr_is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?; - if !name.is_empty() && !name.to_string_lossy().contains('=') { - let value = this.read_os_str_from_c_str(value_ptr)?; - new = Some((name.to_owned(), value.to_owned())); - } - } - if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_c_str(&name, &value, this)?; - if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; - } - this.update_environ()?; - Ok(0) // return zero on success - } else { - // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - Ok(-1) + pub(crate) fn unix_mut(&mut self) -> &mut UnixEnvVars<'tcx> { + match self { + EnvVars::Unix(env) => env, + _ => unreachable!(), } } - #[allow(non_snake_case)] - fn SetEnvironmentVariableW( - &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - value_op: &OpTy<'tcx, Provenance>, // LPCWSTR - ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - this.assert_target_os("windows", "SetEnvironmentVariableW"); - - let name_ptr = this.read_pointer(name_op)?; - let value_ptr = this.read_pointer(value_op)?; - - if this.ptr_is_null(name_ptr)? { - // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. - throw_ub_format!("pointer to environment variable name is NULL"); - } - - let name = this.read_os_str_from_wide_str(name_ptr)?; - if name.is_empty() { - throw_unsup_format!("environment variable name is an empty string"); - } else if name.to_string_lossy().contains('=') { - throw_unsup_format!("environment variable name contains '='"); - } else if this.ptr_is_null(value_ptr)? { - // Delete environment variable `{name}` - if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; - } - Ok(this.eval_windows("c", "TRUE")) - } else { - let value = this.read_os_str_from_wide_str(value_ptr)?; - let var_ptr = alloc_env_var_as_wide_str(&name, &value, this)?; - if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; - } - Ok(this.eval_windows("c", "TRUE")) + pub(crate) fn windows(&self) -> &WindowsEnvVars { + match self { + EnvVars::Windows(env) => env, + _ => unreachable!(), } } - fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("unsetenv"); - - let name_ptr = this.read_pointer(name_op)?; - let mut success = None; - if !this.ptr_is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); - if !name.is_empty() && !name.to_string_lossy().contains('=') { - success = Some(this.machine.env_vars.map.remove(&name)); - } - } - if let Some(old) = success { - if let Some(var) = old { - this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; - } - this.update_environ()?; - Ok(0) - } else { - // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - Ok(-1) + pub(crate) fn windows_mut(&mut self) -> &mut WindowsEnvVars { + match self { + EnvVars::Windows(env) => env, + _ => unreachable!(), } } - - fn getcwd( - &mut self, - buf_op: &OpTy<'tcx, Provenance>, - size_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("getcwd"); - - let buf = this.read_pointer(buf_op)?; - let size = this.read_target_usize(size_op)?; - - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`getcwd`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(Pointer::null()); - } - - // If we cannot get the current directory, we return null - match env::current_dir() { - Ok(cwd) => { - if this.write_path_to_c_str(&cwd, buf, size)?.0 { - return Ok(buf); - } - let erange = this.eval_libc("ERANGE"); - this.set_last_error(erange)?; - } - Err(e) => this.set_last_error_from_io_error(e.kind())?, - } - - Ok(Pointer::null()) - } - - #[allow(non_snake_case)] - fn GetCurrentDirectoryW( - &mut self, - size_op: &OpTy<'tcx, Provenance>, // DWORD - buf_op: &OpTy<'tcx, Provenance>, // LPTSTR - ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - this.assert_target_os("windows", "GetCurrentDirectoryW"); - - let size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let buf = this.read_pointer(buf_op)?; - - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(Scalar::from_u32(0)); - } - - // If we cannot get the current directory, we return 0 - match env::current_dir() { - Ok(cwd) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error - return Ok(Scalar::from_u32(windows_check_buffer_size( - this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?, - ))); - } - Err(e) => this.set_last_error_from_io_error(e.kind())?, - } - Ok(Scalar::from_u32(0)) - } - - fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("chdir"); - - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; - - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`chdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - - return Ok(-1); - } - - match env::set_current_dir(path) { - Ok(()) => Ok(0), - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(-1) - } - } - } - - #[allow(non_snake_case)] - fn SetCurrentDirectoryW( - &mut self, - path_op: &OpTy<'tcx, Provenance>, // LPCTSTR - ) -> InterpResult<'tcx, Scalar> { - // ^ Returns BOOL (i32 on Windows) - - let this = self.eval_context_mut(); - this.assert_target_os("windows", "SetCurrentDirectoryW"); - - let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; - - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - - return Ok(this.eval_windows("c", "FALSE")); - } - - match env::set_current_dir(path) { - Ok(()) => Ok(this.eval_windows("c", "TRUE")), - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(this.eval_windows("c", "FALSE")) - } - } - } - - /// Updates the `environ` static. - /// The first time it gets called, also initializes `extra.environ`. - fn update_environ(&mut self) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - // Deallocate the old environ list, if any. - let environ = this.machine.env_vars.environ.as_ref().unwrap().clone(); - let old_vars_ptr = this.read_pointer(&environ)?; - if !this.ptr_is_null(old_vars_ptr)? { - this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; - } - - // Collect all the pointers to each variable in a vector. - let mut vars: Vec>> = - this.machine.env_vars.map.values().copied().collect(); - // Add the trailing null pointer. - vars.push(Pointer::null()); - // Make an array with all these pointers inside Miri. - let tcx = this.tcx; - let vars_layout = this.layout_of(Ty::new_array( - tcx.tcx, - this.machine.layouts.mut_raw_ptr.ty, - u64::try_from(vars.len()).unwrap(), - ))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; - for (idx, var) in vars.into_iter().enumerate() { - let place = this.project_field(&vars_place, idx)?; - this.write_pointer(var, &place)?; - } - this.write_pointer(vars_place.ptr(), &environ)?; - - Ok(()) - } - - /// Reads from the `environ` static. - /// We don't actually care about the result, but we care about this potentially causing a data race. - fn read_environ(&self) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - let environ = this.machine.env_vars.environ.as_ref().unwrap(); - let _vars_ptr = this.read_pointer(environ)?; - Ok(()) - } - - fn getpid(&mut self) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os_is_unix("getpid"); - - this.check_no_isolation("`getpid`")?; - - // The reason we need to do this wacky of a conversion is because - // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. - // So we un-do the conversion that stdlib does and turn it back into an i32. - #[allow(clippy::cast_possible_wrap)] - Ok(std::process::id() as i32) - } - - #[allow(non_snake_case)] - fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { - let this = self.eval_context_mut(); - this.assert_target_os("windows", "GetCurrentProcessId"); - - this.check_no_isolation("`GetCurrentProcessId`")?; - - Ok(std::process::id()) - } } + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {} diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 7c4a54fb461a8..442338a6117d8 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -47,20 +47,14 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"], )?; // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); + let environ = this.machine.env_vars.unix().environ(); + Self::add_extern_static(this, "environ", environ); } "freebsd" => { Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?; // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); + let environ = this.machine.env_vars.unix().environ(); + Self::add_extern_static(this, "environ", environ); } "android" => { Self::null_ptr_extern_statics(this, &["bsd_signal"])?; diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index a2fc4f0f761af..9a0671430d438 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -163,7 +163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } Op::Numeric(name) => { - this.numeric_intrinsic(name, op.to_scalar(), op.layout)? + this.numeric_intrinsic(name, op.to_scalar(), op.layout, op.layout)? } }; this.write_scalar(val, &dest)?; diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 3e8c35d48aee0..5fcea9ced6914 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -72,11 +72,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { u16vec_to_osstring(u16_vec) } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does include the null terminator. + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what the + /// Unix APIs usually handle. Returns `(success, full_len)`, where length includes the null + /// terminator. On failure, nothing is written. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, @@ -87,19 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { self.eval_context_mut().write_c_str(bytes, ptr, size) } - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the - /// Windows APIs usually handle. - /// - /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false, - /// length))` without trying to write if `size` is not large enough to fit the contents of - /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process - /// was successful. The string length returned does include the null terminator. Length is - /// measured in units of `u16.` - /// - /// If `truncate == true`, then in case `size` is not large enough it *will* write the first - /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`). - /// The return value is still `(false, length)` in that case. - fn write_os_str_to_wide_str( + /// Internal helper to share code between `write_os_str_to_wide_str` and + /// `write_os_str_to_wide_str_truncated`. + fn write_os_str_to_wide_str_helper( &mut self, os_str: &OsStr, ptr: Pointer>, @@ -133,6 +121,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok((written, size_needed)) } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the + /// Windows APIs usually handle. Returns `(success, full_len)`, where length is measured + /// in units of `u16` and includes the null terminator. On failure, nothing is written. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + ptr: Pointer>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false) + } + + /// Like `write_os_str_to_wide_str`, but on failure as much as possible is written into + /// the buffer (always with a null terminator). + fn write_os_str_to_wide_str_truncated( + &mut self, + os_str: &OsStr, + ptr: Pointer>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true) + } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, @@ -160,9 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; - let (written, _) = self - .write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false) - .unwrap(); + let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap(); assert!(written); Ok(arg_place.ptr()) } @@ -217,12 +226,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { path: &Path, ptr: Pointer>, size: u64, - truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, ptr, size, truncate) + this.write_os_str_to_wide_str(&os_str, ptr, size) + } + + /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), + /// adjusting path separators if needed. + fn write_path_to_wide_str_truncated( + &mut self, + path: &Path, + ptr: Pointer>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + let os_str = + this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.write_os_str_to_wide_str_truncated(&os_str, ptr, size) } /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 1126c900226df..dfdf58470d63a 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -1,5 +1,9 @@ +use std::ffi::OsString; +use std::fmt::Write; use std::time::{Duration, SystemTime}; +use chrono::{DateTime, Datelike, Local, Timelike, Utc}; + use crate::concurrency::thread::MachineCallback; use crate::*; @@ -107,6 +111,80 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(0) } + // The localtime() function shall convert the time in seconds since the Epoch pointed to by + // timer into a broken-down time, expressed as a local time. + // https://linux.die.net/man/3/localtime_r + fn localtime_r( + &mut self, + timep: &OpTy<'tcx, Provenance>, + result_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + + this.assert_target_os_is_unix("localtime_r"); + this.check_no_isolation("`localtime_r`")?; + + let timep = this.deref_pointer(timep)?; + let result = this.deref_pointer_as(result_op, this.libc_ty_layout("tm"))?; + + // The input "represents the number of seconds elapsed since the Epoch, + // 1970-01-01 00:00:00 +0000 (UTC)". + let sec_since_epoch: i64 = this + .read_scalar(&timep)? + .to_int(this.libc_ty_layout("time_t").size)? + .try_into() + .unwrap(); + let dt_utc: DateTime = + DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); + // Convert that to local time, then return the broken-down time value. + let dt: DateTime = DateTime::from(dt_utc); + + // This value is always set to -1, because there is no way to know if dst is in effect with + // chrono crate yet. + // This may not be consistent with libc::localtime_r's result. + let tm_isdst = -1; + + // tm_zone represents the timezone value in the form of: +0730, +08, -0730 or -08. + // This may not be consistent with libc::localtime_r's result. + let offset_in_second = Local::now().offset().local_minus_utc(); + let tm_gmtoff = offset_in_second; + let mut tm_zone = String::new(); + if offset_in_second < 0 { + tm_zone.push('-'); + } else { + tm_zone.push('+'); + } + let offset_hour = offset_in_second.abs() / 3600; + write!(tm_zone, "{:02}", offset_hour).unwrap(); + let offset_min = (offset_in_second.abs() % 3600) / 60; + if offset_min != 0 { + write!(tm_zone, "{:02}", offset_min).unwrap(); + } + + // FIXME: String de-duplication is needed so that we only allocate this string only once + // even when there are multiple calls to this function. + let tm_zone_ptr = + this.alloc_os_str_as_c_str(&OsString::from(tm_zone), MiriMemoryKind::Machine.into())?; + + this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; + this.write_int_fields_named( + &[ + ("tm_sec", dt.second().into()), + ("tm_min", dt.minute().into()), + ("tm_hour", dt.hour().into()), + ("tm_mday", dt.day().into()), + ("tm_mon", dt.month0().into()), + ("tm_year", dt.year().checked_sub(1900).unwrap().into()), + ("tm_wday", dt.weekday().num_days_from_sunday().into()), + ("tm_yday", dt.ordinal0().into()), + ("tm_isdst", tm_isdst), + ("tm_gmtoff", tm_gmtoff.into()), + ], + &result, + )?; + + Ok(result.ptr()) + } #[allow(non_snake_case, clippy::arithmetic_side_effects)] fn GetSystemTimeAsFileTime( &mut self, diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs new file mode 100644 index 0000000000000..128f0dcafa942 --- /dev/null +++ b/src/tools/miri/src/shims/unix/env.rs @@ -0,0 +1,276 @@ +use std::env; +use std::ffi::{OsStr, OsString}; +use std::io::ErrorKind; +use std::mem; + +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::Ty; +use rustc_target::abi::Size; + +use crate::*; + +pub struct UnixEnvVars<'tcx> { + /// Stores pointers to the environment variables. These variables must be stored as + /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. + map: FxHashMap>>, + + /// Place where the `environ` static is stored. Lazily initialized, but then never changes. + environ: MPlaceTy<'tcx, Provenance>, +} + +impl VisitProvenance for UnixEnvVars<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + let UnixEnvVars { map, environ } = self; + + environ.visit_provenance(visit); + for ptr in map.values() { + ptr.visit_provenance(visit); + } + } +} + +impl<'tcx> UnixEnvVars<'tcx> { + pub(crate) fn new<'mir>( + ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + env_vars: FxHashMap, + ) -> InterpResult<'tcx, Self> { + // Allocate memory for all these env vars. + let mut env_vars_machine = FxHashMap::default(); + for (name, val) in env_vars.into_iter() { + let ptr = alloc_env_var(ecx, &name, &val)?; + env_vars_machine.insert(name, ptr); + } + + // This is memory backing an extern static, hence `ExternStatic`, not `Env`. + let layout = ecx.machine.layouts.mut_raw_ptr; + let environ = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + let environ_block = alloc_environ_block(ecx, env_vars_machine.values().copied().collect())?; + ecx.write_pointer(environ_block, &environ)?; + + Ok(UnixEnvVars { map: env_vars_machine, environ }) + } + + pub(crate) fn cleanup<'mir>( + ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + ) -> InterpResult<'tcx> { + // Deallocate individual env vars. + let env_vars = mem::take(&mut ecx.machine.env_vars.unix_mut().map); + for (_name, ptr) in env_vars { + ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?; + } + // Deallocate environ var list. + let environ = &ecx.machine.env_vars.unix().environ; + let old_vars_ptr = ecx.read_pointer(environ)?; + ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + + Ok(()) + } + + pub(crate) fn environ(&self) -> Pointer> { + self.environ.ptr() + } +} + +fn alloc_env_var<'mir, 'tcx>( + ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + value: &OsStr, +) -> InterpResult<'tcx, Pointer>> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) +} + +/// Allocates an `environ` block with the given list of pointers. +fn alloc_environ_block<'mir, 'tcx>( + ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + mut vars: Vec>>, +) -> InterpResult<'tcx, Pointer>> { + // Add trailing null. + vars.push(Pointer::null()); + // Make an array with all these pointers inside Miri. + let vars_layout = ecx.layout_of(Ty::new_array( + *ecx.tcx, + ecx.machine.layouts.mut_raw_ptr.ty, + u64::try_from(vars.len()).unwrap(), + ))?; + let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; + for (idx, var) in vars.into_iter().enumerate() { + let place = ecx.project_field(&vars_place, idx)?; + ecx.write_pointer(var, &place)?; + } + Ok(vars_place.ptr()) +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + fn getenv( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("getenv"); + + let name_ptr = this.read_pointer(name_op)?; + let name = this.read_os_str_from_c_str(name_ptr)?; + + // We don't care about the value as we have the `map` to keep track of everything, + // but we do want to do this read so it shows up as a data race. + let _vars_ptr = this.read_pointer(&this.machine.env_vars.unix().environ)?; + Ok(match this.machine.env_vars.unix().map.get(name) { + Some(var_ptr) => { + // The offset is used to strip the "{name}=" part of the string. + var_ptr.offset( + Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), + this, + )? + } + None => Pointer::null(), + }) + } + + fn setenv( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + value_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("setenv"); + + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; + + let mut new = None; + if !this.ptr_is_null(name_ptr)? { + let name = this.read_os_str_from_c_str(name_ptr)?; + if !name.is_empty() && !name.to_string_lossy().contains('=') { + let value = this.read_os_str_from_c_str(value_ptr)?; + new = Some((name.to_owned(), value.to_owned())); + } + } + if let Some((name, value)) = new { + let var_ptr = alloc_env_var(this, &name, &value)?; + if let Some(var) = this.machine.env_vars.unix_mut().map.insert(name, var_ptr) { + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; + } + this.update_environ()?; + Ok(0) // return zero on success + } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + Ok(-1) + } + } + + fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("unsetenv"); + + let name_ptr = this.read_pointer(name_op)?; + let mut success = None; + if !this.ptr_is_null(name_ptr)? { + let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); + if !name.is_empty() && !name.to_string_lossy().contains('=') { + success = Some(this.machine.env_vars.unix_mut().map.remove(&name)); + } + } + if let Some(old) = success { + if let Some(var) = old { + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; + } + this.update_environ()?; + Ok(0) + } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + Ok(-1) + } + } + + fn getcwd( + &mut self, + buf_op: &OpTy<'tcx, Provenance>, + size_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("getcwd"); + + let buf = this.read_pointer(buf_op)?; + let size = this.read_target_usize(size_op)?; + + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`getcwd`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(Pointer::null()); + } + + // If we cannot get the current directory, we return null + match env::current_dir() { + Ok(cwd) => { + if this.write_path_to_c_str(&cwd, buf, size)?.0 { + return Ok(buf); + } + let erange = this.eval_libc("ERANGE"); + this.set_last_error(erange)?; + } + Err(e) => this.set_last_error_from_io_error(e.kind())?, + } + + Ok(Pointer::null()) + } + + fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("chdir"); + + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`chdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + + return Ok(-1); + } + + match env::set_current_dir(path) { + Ok(()) => Ok(0), + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(-1) + } + } + } + + /// Updates the `environ` static. + fn update_environ(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // Deallocate the old environ list. + let environ = this.machine.env_vars.unix().environ.clone(); + let old_vars_ptr = this.read_pointer(&environ)?; + this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + + // Write the new list. + let vals = this.machine.env_vars.unix().map.values().copied().collect(); + let environ_block = alloc_environ_block(this, vals)?; + this.write_pointer(environ_block, &environ)?; + + Ok(()) + } + + fn getpid(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("getpid"); + + this.check_no_isolation("`getpid`")?; + + // The reason we need to do this wacky of a conversion is because + // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. + // So we un-do the conversion that stdlib does and turn it back into an i32. + #[allow(clippy::cast_possible_wrap)] + Ok(std::process::id() as i32) + } +} diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index c72d3bb3df4a8..bd299aaa1253a 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -234,6 +234,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "localtime_r" => { + let [timep, result_op] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?; + let result = this.localtime_r(timep, result_op)?; + this.write_pointer(result, dest)?; + } "clock_gettime" => { let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index ec2922d027501..3948216f7297c 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // old_address must be a multiple of the page size #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 { // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 53a02bf5e0b5a..66a8dce753fb1 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -74,15 +74,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Environment related shims "_NSGetEnviron" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_pointer( - this.machine - .env_vars - .environ - .as_ref() - .expect("machine must be initialized") - .ptr(), - dest, - )?; + let environ = this.machine.env_vars.unix().environ(); + this.write_pointer(environ, dest)?; } // Time related shims diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index d3470893dbbca..f52dc23656db6 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -53,11 +53,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // First, we do some basic argument validation as required by mmap if (flags & (map_private | map_shared)).count_ones() != 1 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } if length == 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // // Miri doesn't support MAP_FIXED or any any protections other than PROT_READ|PROT_WRITE. if flags & map_fixed != 0 || prot != prot_read | prot_write { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("ENOTSUP")))?; + this.set_last_error(this.eval_libc("ENOTSUP"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -96,11 +96,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let align = this.machine.page_align(); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); }; if map_length > this.target_usize_max() { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -131,16 +131,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // as a dealloc. #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(Scalar::from_i32(-1)); }; if length > this.target_usize_max() { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 2bc41e1a62d62..144593aa2fc08 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -1,5 +1,6 @@ pub mod foreign_items; +mod env; mod fd; mod fs; mod mem; @@ -11,9 +12,11 @@ mod freebsd; mod linux; mod macos; +pub use env::UnixEnvVars; pub use fd::{FdTable, FileDescriptor}; pub use fs::DirTable; -// All the unix-specific extension traits +// All the Unix-specific extension traits +pub use env::EvalContextExt as _; pub use fd::EvalContextExt as _; pub use fs::EvalContextExt as _; pub use mem::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs new file mode 100644 index 0000000000000..e91623ac87160 --- /dev/null +++ b/src/tools/miri/src/shims/windows/env.rs @@ -0,0 +1,257 @@ +use std::env; +use std::ffi::OsString; +use std::io::ErrorKind; + +use rustc_data_structures::fx::FxHashMap; + +use crate::*; +use helpers::windows_check_buffer_size; + +#[derive(Default)] +pub struct WindowsEnvVars { + /// Stores the environment varialbles. + map: FxHashMap, +} + +impl VisitProvenance for WindowsEnvVars { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + let WindowsEnvVars { map: _ } = self; + } +} + +impl WindowsEnvVars { + pub(crate) fn new<'mir, 'tcx>( + _ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + env_vars: FxHashMap, + ) -> InterpResult<'tcx, Self> { + Ok(Self { map: env_vars }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + #[allow(non_snake_case)] + fn GetEnvironmentVariableW( + &mut self, + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + buf_op: &OpTy<'tcx, Provenance>, // LPWSTR + size_op: &OpTy<'tcx, Provenance>, // DWORD + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns DWORD (u32 on Windows) + + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentVariableW"); + + let name_ptr = this.read_pointer(name_op)?; + let buf_ptr = this.read_pointer(buf_op)?; + let buf_size = this.read_scalar(size_op)?.to_u32()?; // in characters + + let name = this.read_os_str_from_wide_str(name_ptr)?; + Ok(match this.machine.env_vars.windows().map.get(&name).cloned() { + Some(val) => { + Scalar::from_u32(windows_check_buffer_size(this.write_os_str_to_wide_str( + &val, + buf_ptr, + buf_size.into(), + )?)) + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. + } + None => { + let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND"); + this.set_last_error(envvar_not_found)?; + Scalar::from_u32(0) // return zero upon failure + } + }) + } + + #[allow(non_snake_case)] + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentStringsW"); + + // Info on layout of environment blocks in Windows: + // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables + let mut env_vars = std::ffi::OsString::new(); + for (name, value) in this.machine.env_vars.windows().map.iter() { + env_vars.push(name); + env_vars.push("="); + env_vars.push(value); + env_vars.push("\0"); + } + // Allocate environment block & Store environment variables to environment block. + // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. + let envblock_ptr = + this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?; + // If the function succeeds, the return value is a pointer to the environment block of the current process. + Ok(envblock_ptr) + } + + #[allow(non_snake_case)] + fn FreeEnvironmentStringsW( + &mut self, + env_block_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "FreeEnvironmentStringsW"); + + let env_block_ptr = this.read_pointer(env_block_op)?; + this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into())?; + // If the function succeeds, the return value is nonzero. + Ok(Scalar::from_i32(1)) + } + + #[allow(non_snake_case)] + fn SetEnvironmentVariableW( + &mut self, + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + value_op: &OpTy<'tcx, Provenance>, // LPCWSTR + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "SetEnvironmentVariableW"); + + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; + + if this.ptr_is_null(name_ptr)? { + // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. + throw_ub_format!("pointer to environment variable name is NULL"); + } + + let name = this.read_os_str_from_wide_str(name_ptr)?; + if name.is_empty() { + throw_unsup_format!("environment variable name is an empty string"); + } else if name.to_string_lossy().contains('=') { + throw_unsup_format!("environment variable name contains '='"); + } else if this.ptr_is_null(value_ptr)? { + // Delete environment variable `{name}` if it exists. + this.machine.env_vars.windows_mut().map.remove(&name); + Ok(this.eval_windows("c", "TRUE")) + } else { + let value = this.read_os_str_from_wide_str(value_ptr)?; + this.machine.env_vars.windows_mut().map.insert(name, value); + Ok(this.eval_windows("c", "TRUE")) + } + } + + #[allow(non_snake_case)] + fn GetCurrentDirectoryW( + &mut self, + size_op: &OpTy<'tcx, Provenance>, // DWORD + buf_op: &OpTy<'tcx, Provenance>, // LPTSTR + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentDirectoryW"); + + let size = u64::from(this.read_scalar(size_op)?.to_u32()?); + let buf = this.read_pointer(buf_op)?; + + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(Scalar::from_u32(0)); + } + + // If we cannot get the current directory, we return 0 + match env::current_dir() { + Ok(cwd) => { + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. + return Ok(Scalar::from_u32(windows_check_buffer_size( + this.write_path_to_wide_str(&cwd, buf, size)?, + ))); + } + Err(e) => this.set_last_error_from_io_error(e.kind())?, + } + Ok(Scalar::from_u32(0)) + } + + #[allow(non_snake_case)] + fn SetCurrentDirectoryW( + &mut self, + path_op: &OpTy<'tcx, Provenance>, // LPCTSTR + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + + let this = self.eval_context_mut(); + this.assert_target_os("windows", "SetCurrentDirectoryW"); + + let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; + + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + + return Ok(this.eval_windows("c", "FALSE")); + } + + match env::set_current_dir(path) { + Ok(()) => Ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(this.eval_windows("c", "FALSE")) + } + } + } + + #[allow(non_snake_case)] + fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentProcessId"); + this.check_no_isolation("`GetCurrentProcessId`")?; + + Ok(std::process::id()) + } + + #[allow(non_snake_case)] + fn GetUserProfileDirectoryW( + &mut self, + token: &OpTy<'tcx, Provenance>, // HANDLE + buf: &OpTy<'tcx, Provenance>, // LPWSTR + size: &OpTy<'tcx, Provenance>, // LPDWORD + ) -> InterpResult<'tcx, Scalar> // returns BOOL + { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetUserProfileDirectoryW"); + this.check_no_isolation("`GetUserProfileDirectoryW`")?; + + let token = this.read_target_isize(token)?; + let buf = this.read_pointer(buf)?; + let size = this.deref_pointer(size)?; + + if token != -4 { + throw_unsup_format!( + "GetUserProfileDirectoryW: only CURRENT_PROCESS_TOKEN is supported" + ); + } + + // See for docs. + Ok(match directories::UserDirs::new() { + Some(dirs) => { + let home = dirs.home_dir(); + let size_avail = if this.ptr_is_null(size.ptr())? { + 0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length + } else { + this.read_scalar(&size)?.to_u32()? + }; + // Of course we cannot use `windows_check_buffer_size` here since this uses + // a different method for dealing with a too-small buffer than the other functions... + let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?; + // The Windows docs just say that this is written on failure. But std + // seems to rely on it always being written. + this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?; + if success { + Scalar::from_i32(1) // return TRUE + } else { + this.set_last_error(this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER"))?; + Scalar::from_i32(0) // return FALSE + } + } + None => { + // We have to pick some error code. + this.set_last_error(this.eval_windows("c", "ERROR_BAD_USER_PROFILE"))?; + Scalar::from_i32(0) // return FALSE + } + }) + } +} diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index ec4c61014877e..e8ae80261c662 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -10,11 +10,10 @@ use rustc_target::spec::abi::Abi; use crate::shims::alloc::EvalContextExt as _; use crate::shims::os_str::bytes_to_os_str; +use crate::shims::windows::*; use crate::*; use shims::foreign_items::EmulateForeignItemResult; -use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; -use shims::windows::sync::EvalContextExt as _; -use shims::windows::thread::EvalContextExt as _; +use shims::windows::handle::{Handle, PseudoHandle}; fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols @@ -135,6 +134,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(result, dest)?; } + "GetUserProfileDirectoryW" => { + let [token, buf, size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let result = this.GetUserProfileDirectoryW(token, buf, size)?; + this.write_scalar(result, dest)?; + } // File related shims "NtWriteFile" => { @@ -225,15 +230,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Scalar::from_u32(0) // return zero upon failure } Ok(abs_filename) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error Scalar::from_u32(helpers::windows_check_buffer_size( - this.write_path_to_wide_str( - &abs_filename, - buffer, - size.into(), - /*truncate*/ false, - )?, + this.write_path_to_wide_str(&abs_filename, buffer, size.into())?, )) + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. } }; this.write_scalar(result, dest)?; @@ -601,15 +602,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Using the host current_exe is a bit off, but consistent with Linux // (where stdlib reads /proc/self/exe). - // Unfortunately this Windows function has a crazy behavior so we can't just use - // `write_path_to_wide_str`... let path = std::env::current_exe().unwrap(); - let (all_written, size_needed) = this.write_path_to_wide_str( - &path, - filename, - size.into(), - /*truncate*/ true, - )?; + let (all_written, size_needed) = + this.write_path_to_wide_str_truncated(&path, filename, size.into())?; if all_written { // If the function succeeds, the return value is the length of the string that @@ -649,12 +644,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Some(err) => format!("{err}"), None => format!(""), }; - let (complete, length) = this.write_os_str_to_wide_str( - OsStr::new(&formatted), - buffer, - size.into(), - /*trunacte*/ false, - )?; + let (complete, length) = + this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?; if !complete { // The API docs don't say what happens when the buffer is not big enough... // Let's just bail. diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs index 7688abe412b99..65f682b9dad9a 100644 --- a/src/tools/miri/src/shims/windows/mod.rs +++ b/src/tools/miri/src/shims/windows/mod.rs @@ -1,5 +1,13 @@ pub mod foreign_items; +mod env; mod handle; mod sync; mod thread; + +pub use env::WindowsEnvVars; +// All the Windows-specific extension traits +pub use env::EvalContextExt as _; +pub use handle::EvalContextExt as _; +pub use sync::EvalContextExt as _; +pub use thread::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 23c78647b9c46..41c20d768f77a 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -7,7 +7,8 @@ use rustc_target::spec::abi::Abi; use super::{ bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, horizontal_bin_op, - round_all, test_bits_masked, test_high_bits_masked, unary_op_ps, FloatBinOp, FloatUnaryOp, + mask_load, mask_store, round_all, test_bits_masked, test_high_bits_masked, unary_op_ps, + FloatBinOp, FloatUnaryOp, }; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -347,71 +348,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: Ok(EmulateForeignItemResult::NeedsJumping) } } - -/// Conditionally loads from `ptr` according the high bit of each -/// element of `mask`. `ptr` does not need to be aligned. -fn mask_load<'tcx>( - this: &mut crate::MiriInterpCx<'_, 'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, mask_len); - - let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); - - let ptr = this.read_pointer(ptr)?; - for i in 0..dest_len { - let mask = this.project_index(&mask, i)?; - let dest = this.project_index(&dest, i)?; - - if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] - let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); - // Unaligned copy, which is what we want. - this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; - } else { - this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; - } - } - - Ok(()) -} - -/// Conditionally stores into `ptr` according the high bit of each -/// element of `mask`. `ptr` does not need to be aligned. -fn mask_store<'tcx>( - this: &mut crate::MiriInterpCx<'_, 'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - value: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (value, value_len) = this.operand_to_simd(value)?; - - assert_eq!(value_len, mask_len); - - let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); - - let ptr = this.read_pointer(ptr)?; - for i in 0..value_len { - let mask = this.project_index(&mask, i)?; - let value = this.project_index(&value, i)?; - - if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] - let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); - // Unaligned copy, which is what we want. - this.mem_copy(value.ptr(), ptr, value.layout.size, /*nonoverlapping*/ true)?; - } - } - - Ok(()) -} diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs new file mode 100644 index 0000000000000..bbf53f9f1e5d0 --- /dev/null +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -0,0 +1,444 @@ +use crate::rustc_middle::ty::layout::LayoutOf as _; +use rustc_middle::mir; +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use super::{ + horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, packusdw, + packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, ShiftOp, +}; +use crate::*; +use shims::foreign_items::EmulateForeignItemResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ + fn emulate_x86_avx2_intrinsic( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateForeignItemResult> { + let this = self.eval_context_mut(); + this.expect_target_feature_for_intrinsic(link_name, "avx2")?; + // Prefix should have already been checked. + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx2.").unwrap(); + + match unprefixed_name { + // Used to implement the _mm256_abs_epi{8,16,32} functions. + // Calculates the absolute value of packed 8/16/32-bit integers. + "pabs.b" | "pabs.w" | "pabs.d" => { + let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + int_abs(this, op, dest)?; + } + // Used to implement the _mm256_h{add,adds,sub}_epi{16,32} functions. + // Horizontally add / add with saturation / subtract adjacent 16/32-bit + // integer values in `left` and `right`. + "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (which, saturating) = match unprefixed_name { + "phadd.w" | "phadd.d" => (mir::BinOp::Add, false), + "phadd.sw" => (mir::BinOp::Add, true), + "phsub.w" | "phsub.d" => (mir::BinOp::Sub, false), + "phsub.sw" => (mir::BinOp::Sub, true), + _ => unreachable!(), + }; + + horizontal_bin_op(this, which, saturating, left, right, dest)?; + } + // Used to implement `_mm{,_mask}_{i32,i64}gather_{epi32,epi64,pd,ps}` functions + // Gathers elements from `slice` using `offsets * scale` as indices. + // When the highest bit of the corresponding element of `mask` is 0, + // the value is copied from `src` instead. + "gather.d.d" | "gather.d.d.256" | "gather.d.q" | "gather.d.q.256" | "gather.q.d" + | "gather.q.d.256" | "gather.q.q" | "gather.q.q.256" | "gather.d.pd" + | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps" + | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => { + let [src, slice, offsets, mask, scale] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + assert_eq!(dest.layout, src.layout); + + let (src, _) = this.operand_to_simd(src)?; + let (offsets, offsets_len) = this.operand_to_simd(offsets)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + // There are cases like dest: i32x4, offsets: i64x2 + let actual_len = dest_len.min(offsets_len); + + assert_eq!(dest_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let scale = this.read_scalar(scale)?.to_i8()?; + if !matches!(scale, 1 | 2 | 4 | 8) { + throw_unsup_format!("invalid gather scale {scale}"); + } + let scale = i64::from(scale); + + let slice = this.read_pointer(slice)?; + for i in 0..actual_len { + let mask = this.project_index(&mask, i)?; + let dest = this.project_index(&dest, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let offset = this.project_index(&offsets, i)?; + let offset = + i64::try_from(this.read_scalar(&offset)?.to_int(offset.layout.size)?) + .unwrap(); + let ptr = slice + .wrapping_signed_offset(offset.checked_mul(scale).unwrap(), &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy( + ptr, + dest.ptr(), + dest.layout.size, + /*nonoverlapping*/ true, + )?; + } else { + this.copy_op(&this.project_index(&src, i)?, &dest)?; + } + } + for i in actual_len..dest_len { + let dest = this.project_index(&dest, i)?; + this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; + } + } + // Used to implement the _mm256_madd_epi16 function. + // Multiplies packed signed 16-bit integers in `left` and `right`, producing + // intermediate signed 32-bit integers. Horizontally add adjacent pairs of + // intermediate 32-bit integers, and pack the results in `dest`. + "pmadd.wd" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + + for i in 0..dest_len { + let j1 = i.checked_mul(2).unwrap(); + let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; + let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; + + let j2 = j1.checked_add(1).unwrap(); + let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; + let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; + + let dest = this.project_index(&dest, i)?; + + // Multiplications are i16*i16->i32, which will not overflow. + let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap(); + let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap(); + // However, this addition can overflow in the most extreme case + // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 + let res = mul1.wrapping_add(mul2); + + this.write_scalar(Scalar::from_i32(res), &dest)?; + } + } + // Used to implement the _mm256_maddubs_epi16 function. + // Multiplies packed 8-bit unsigned integers from `left` and packed + // signed 8-bit integers from `right` into 16-bit signed integers. Then, + // the saturating sum of the products with indices `2*i` and `2*i+1` + // produces the output at index `i`. + "pmadd.ub.sw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + + for i in 0..dest_len { + let j1 = i.checked_mul(2).unwrap(); + let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?; + let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?; + + let j2 = j1.checked_add(1).unwrap(); + let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?; + let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?; + + let dest = this.project_index(&dest, i)?; + + // Multiplication of a u8 and an i8 into an i16 cannot overflow. + let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap(); + let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap(); + let res = mul1.saturating_add(mul2); + + this.write_scalar(Scalar::from_i16(res), &dest)?; + } + } + // Used to implement the _mm_maskload_epi32, _mm_maskload_epi64, + // _mm256_maskload_epi32 and _mm256_maskload_epi64 functions. + // For the element `i`, if the high bit of the `i`-th element of `mask` + // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is + // loaded. + "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => { + let [ptr, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mask_load(this, ptr, mask, dest)?; + } + // Used to implement the _mm_maskstore_epi32, _mm_maskstore_epi64, + // _mm256_maskstore_epi32 and _mm256_maskstore_epi64 functions. + // For the element `i`, if the high bit of the element `i`-th of `mask` + // is one, it is stored into `ptr.wapping_add(i)`. + // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. + "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => { + let [ptr, mask, value] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mask_store(this, ptr, mask, value)?; + } + // Used to implement the _mm256_mpsadbw_epu8 function. + // Compute the sum of absolute differences of quadruplets of unsigned + // 8-bit integers in `left` and `right`, and store the 16-bit results + // in `right`. Quadruplets are selected from `left` and `right` with + // offsets specified in `imm`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 + "mpsadbw" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mpsadbw(this, left, right, imm, dest)?; + } + // Used to implement the _mm256_mulhrs_epi16 function. + // Multiplies packed 16-bit signed integer values, truncates the 32-bit + // product to the 18 most significant bits by right-shifting, and then + // divides the 18-bit value by 2 (rounding to nearest) by first adding + // 1 and then taking the bits `1..=16`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 + "pmul.hr.sw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + pmulhrsw(this, left, right, dest)?; + } + // Used to implement the _mm256_packs_epi16 function. + // Converts two 16-bit integer vectors to a single 8-bit integer + // vector with signed saturation. + "packsswb" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packsswb(this, left, right, dest)?; + } + // Used to implement the _mm256_packs_epi32 function. + // Converts two 32-bit integer vectors to a single 16-bit integer + // vector with signed saturation. + "packssdw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packssdw(this, left, right, dest)?; + } + // Used to implement the _mm256_packus_epi16 function. + // Converts two 16-bit signed integer vectors to a single 8-bit + // unsigned integer vector with saturation. + "packuswb" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packuswb(this, left, right, dest)?; + } + // Used to implement the _mm256_packus_epi32 function. + // Concatenates two 32-bit signed integer vectors and converts + // the result to a 16-bit unsigned integer vector with saturation. + "packusdw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packusdw(this, left, right, dest)?; + } + // Used to implement the _mm256_permutevar8x32_epi32 and + // _mm256_permutevar8x32_ps function. + // Shuffles `left` using the three low bits of each element of `right` + // as indices. + "permd" | "permps" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u32()?; + let left = this.project_index(&left, (right & 0b111).into())?; + + this.copy_op(&left, &dest)?; + } + } + // Used to implement the _mm256_permute2x128_si256 function. + // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern. + "vperm2i128" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + assert_eq!(left.layout.size.bits(), 256); + assert_eq!(right.layout.size.bits(), 256); + assert_eq!(dest.layout.size.bits(), 256); + + // Transmute to `[i128; 2]` + + let array_layout = + this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.i128, 2))?; + let left = left.transmute(array_layout, this)?; + let right = right.transmute(array_layout, this)?; + let dest = dest.transmute(array_layout, this)?; + + let imm = this.read_scalar(imm)?.to_u8()?; + + for i in 0..2 { + let dest = this.project_index(&dest, i)?; + let src = match (imm >> i.checked_mul(4).unwrap()) & 0b11 { + 0 => this.project_index(&left, 0)?, + 1 => this.project_index(&left, 1)?, + 2 => this.project_index(&right, 0)?, + 3 => this.project_index(&right, 1)?, + _ => unreachable!(), + }; + + this.copy_op(&src, &dest)?; + } + } + // Used to implement the _mm256_sad_epu8 function. + // Compute the absolute differences of packed unsigned 8-bit integers + // in `left` and `right`, then horizontally sum each consecutive 8 + // differences to produce four unsigned 16-bit integers, and pack + // these unsigned 16-bit integers in the low 16 bits of 64-bit elements + // in `dest`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8 + "psad.bw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(left_len, dest_len.checked_mul(8).unwrap()); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + + let mut acc: u16 = 0; + for j in 0..8 { + let src_index = i.checked_mul(8).unwrap().checked_add(j).unwrap(); + + let left = this.project_index(&left, src_index)?; + let left = this.read_scalar(&left)?.to_u8()?; + + let right = this.project_index(&right, src_index)?; + let right = this.read_scalar(&right)?.to_u8()?; + + acc = acc.checked_add(left.abs_diff(right).into()).unwrap(); + } + + this.write_scalar(Scalar::from_u64(acc.into()), &dest)?; + } + } + // Used to implement the _mm256_shuffle_epi8 intrinsic. + // Shuffles bytes from `left` using `right` as pattern. + // Each 128-bit block is shuffled independently. + "pshuf.b" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?; + let dest = this.project_index(&dest, i)?; + + let res = if right & 0x80 == 0 { + // Shuffle each 128-bit (16-byte) block independently. + let j = u64::from(right % 16).checked_add(i & !15).unwrap(); + this.read_scalar(&this.project_index(&left, j)?)? + } else { + // If the highest bit in `right` is 1, write zero. + Scalar::from_u8(0) + }; + + this.write_scalar(res, &dest)?; + } + } + // Used to implement the _mm256_sign_epi{8,16,32} functions. + // Negates elements from `left` when the corresponding element in + // `right` is negative. If an element from `right` is zero, zero + // is writen to the corresponding output element. + // Basically, we multiply `left` with `right.signum()`. + "psign.b" | "psign.w" | "psign.d" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + psign(this, left, right, dest)?; + } + // Used to implement the _mm256_{sll,srl,sra}_epi{16,32,64} functions + // (except _mm256_sra_epi64, which is not available in AVX2). + // Shifts N-bit packed integers in left by the amount in right. + // `right` is as 128-bit vector. but it is interpreted as a single + // 64-bit integer (remaining bits are ignored). + // For logic shifts, when right is larger than N - 1, zero is produced. + // For arithmetic shifts, when right is larger than N - 1, the sign bit + // is copied to remaining bits. + "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" + | "psrl.q" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let which = match unprefixed_name { + "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, + "psrl.w" | "psrl.d" | "psrl.q" => ShiftOp::RightLogic, + "psra.w" | "psra.d" => ShiftOp::RightArith, + _ => unreachable!(), + }; + + shift_simd_by_scalar(this, left, right, which, dest)?; + } + // Used to implement the _mm{,256}_{sllv,srlv,srav}_epi{32,64} functions + // (except _mm{,256}_srav_epi64, which are not available in AVX2). + "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" + | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let which = match unprefixed_name { + "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, + "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" => ShiftOp::RightLogic, + "psrav.d" | "psrav.d.256" => ShiftOp::RightArith, + _ => unreachable!(), + }; + + shift_simd_by_simd(this, left, right, which, dest)?; + } + _ => return Ok(EmulateForeignItemResult::NotSupported), + } + Ok(EmulateForeignItemResult::NeedsJumping) + } +} diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 615821b2e375e..cf4d6a04bec87 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -14,6 +14,7 @@ use shims::foreign_items::EmulateForeignItemResult; mod aesni; mod avx; +mod avx2; mod sse; mod sse2; mod sse3; @@ -136,6 +137,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this, link_name, abi, args, dest, ); } + name if name.starts_with("avx2.") => { + return avx2::EvalContextExt::emulate_x86_avx2_intrinsic( + this, link_name, abi, args, dest, + ); + } _ => return Ok(EmulateForeignItemResult::NotSupported), } @@ -482,7 +488,7 @@ enum ShiftOp { /// /// For logic shifts, when right is larger than BITS - 1, zero is produced. /// For arithmetic right-shifts, when right is larger than BITS - 1, the sign -/// bit is copied to remaining bits. +/// bit is copied to all bits. fn shift_simd_by_scalar<'tcx>( this: &mut crate::MiriInterpCx<'_, 'tcx>, left: &OpTy<'tcx, Provenance>, @@ -534,6 +540,61 @@ fn shift_simd_by_scalar<'tcx>( Ok(()) } +/// Shifts each element of `left` by the corresponding element of `right`. +/// +/// For logic shifts, when right is larger than BITS - 1, zero is produced. +/// For arithmetic right-shifts, when right is larger than BITS - 1, the sign +/// bit is copied to all bits. +fn shift_simd_by_simd<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + which: ShiftOp, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_scalar(&this.project_index(&left, i)?)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?; + let dest = this.project_index(&dest, i)?; + + // It is ok to saturate the value to u32::MAX because any value + // above BITS - 1 will produce the same result. + let shift = u32::try_from(right.to_uint(dest.layout.size)?).unwrap_or(u32::MAX); + + let res = match which { + ShiftOp::Left => { + let left = left.to_uint(dest.layout.size)?; + let res = left.checked_shl(shift).unwrap_or(0); + // `truncate` is needed as left-shift can make the absolute value larger. + Scalar::from_uint(dest.layout.size.truncate(res), dest.layout.size) + } + ShiftOp::RightLogic => { + let left = left.to_uint(dest.layout.size)?; + let res = left.checked_shr(shift).unwrap_or(0); + // No `truncate` needed as right-shift can only make the absolute value smaller. + Scalar::from_uint(res, dest.layout.size) + } + ShiftOp::RightArith => { + let left = left.to_int(dest.layout.size)?; + // On overflow, copy the sign bit to the remaining bits + let res = left.checked_shr(shift).unwrap_or(left >> 127); + // No `truncate` needed as right-shift can only make the absolute value smaller. + Scalar::from_int(res, dest.layout.size) + } + }; + this.write_scalar(res, &dest)?; + } + + Ok(()) +} + /// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts /// the first value. fn extract_first_u64<'tcx>( @@ -650,7 +711,7 @@ fn convert_float_to_int<'tcx>( let dest = this.project_index(&dest, i)?; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE/AVX semantics. + // Fallback to minimum according to SSE/AVX semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); this.write_immediate(*res, &dest)?; @@ -664,6 +725,33 @@ fn convert_float_to_int<'tcx>( Ok(()) } +/// Calculates absolute value of integers in `op` and stores the result in `dest`. +/// +/// In case of overflow (when the operand is the minimum value), the operation +/// will wrap around. +fn int_abs<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + op: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(op_len, dest_len); + + for i in 0..dest_len { + let op = this.read_scalar(&this.project_index(&op, i)?)?; + let dest = this.project_index(&dest, i)?; + + // Converting to a host "i128" works since the input is always signed. + let res = op.to_int(dest.layout.size)?.unsigned_abs(); + + this.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?; + } + + Ok(()) +} + /// Splits `op` (which must be a SIMD vector) into 128-bit chuncks. /// /// Returns a tuple where: @@ -874,3 +962,316 @@ fn test_high_bits_masked<'tcx>( Ok((direct, negated)) } + +/// Conditionally loads from `ptr` according the high bit of each +/// element of `mask`. `ptr` does not need to be aligned. +fn mask_load<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + ptr: &OpTy<'tcx, Provenance>, + mask: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let ptr = this.read_pointer(ptr)?; + for i in 0..dest_len { + let mask = this.project_index(&mask, i)?; + let dest = this.project_index(&dest, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; + } else { + this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; + } + } + + Ok(()) +} + +/// Conditionally stores into `ptr` according the high bit of each +/// element of `mask`. `ptr` does not need to be aligned. +fn mask_store<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + ptr: &OpTy<'tcx, Provenance>, + mask: &OpTy<'tcx, Provenance>, + value: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (value, value_len) = this.operand_to_simd(value)?; + + assert_eq!(value_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let ptr = this.read_pointer(ptr)?; + for i in 0..value_len { + let mask = this.project_index(&mask, i)?; + let value = this.project_index(&value, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy(value.ptr(), ptr, value.layout.size, /*nonoverlapping*/ true)?; + } + } + + Ok(()) +} + +/// Compute the sum of absolute differences of quadruplets of unsigned +/// 8-bit integers in `left` and `right`, and store the 16-bit results +/// in `right`. Quadruplets are selected from `left` and `right` with +/// offsets specified in `imm`. +/// +/// +/// +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn mpsadbw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + imm: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?; + let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; + let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; + + assert_eq!(op_items_per_chunk, dest_items_per_chunk.checked_mul(2).unwrap()); + + let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?; + // Bit 2 of `imm` specifies the offset for indices of `left`. + // The offset is 0 when the bit is 0 or 4 when the bit is 1. + let left_offset = u64::try_from((imm >> 2) & 1).unwrap().checked_mul(4).unwrap(); + // Bits 0..=1 of `imm` specify the offset for indices of + // `right` in blocks of 4 elements. + let right_offset = u64::try_from(imm & 0b11).unwrap().checked_mul(4).unwrap(); + + for i in 0..num_chunks { + let left = this.project_index(&left, i)?; + let right = this.project_index(&right, i)?; + let dest = this.project_index(&dest, i)?; + + for j in 0..dest_items_per_chunk { + let left_offset = left_offset.checked_add(j).unwrap(); + let mut res: u16 = 0; + for k in 0..4 { + let left = this + .read_scalar(&this.project_index(&left, left_offset.checked_add(k).unwrap())?)? + .to_u8()?; + let right = this + .read_scalar( + &this.project_index(&right, right_offset.checked_add(k).unwrap())?, + )? + .to_u8()?; + res = res.checked_add(left.abs_diff(right).into()).unwrap(); + } + this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, j)?)?; + } + } + + Ok(()) +} + +/// Multiplies packed 16-bit signed integer values, truncates the 32-bit +/// product to the 18 most significant bits by right-shifting, and then +/// divides the 18-bit value by 2 (rounding to nearest) by first adding +/// 1 and then taking the bits `1..=16`. +/// +/// +/// +fn pmulhrsw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; + let dest = this.project_index(&dest, i)?; + + let res = + (i32::from(left).checked_mul(right.into()).unwrap() >> 14).checked_add(1).unwrap() >> 1; + + // The result of this operation can overflow a signed 16-bit integer. + // When `left` and `right` are -0x8000, the result is 0x8000. + #[allow(clippy::cast_possible_truncation)] + let res = res as i16; + + this.write_scalar(Scalar::from_i16(res), &dest)?; + } + + Ok(()) +} + +fn pack_generic<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, + f: impl Fn(Scalar) -> InterpResult<'tcx, Scalar>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?; + let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; + let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; + + assert_eq!(dest_items_per_chunk, op_items_per_chunk.checked_mul(2).unwrap()); + + for i in 0..num_chunks { + let left = this.project_index(&left, i)?; + let right = this.project_index(&right, i)?; + let dest = this.project_index(&dest, i)?; + + for j in 0..op_items_per_chunk { + let left = this.read_scalar(&this.project_index(&left, j)?)?; + let right = this.read_scalar(&this.project_index(&right, j)?)?; + let left_dest = this.project_index(&dest, j)?; + let right_dest = + this.project_index(&dest, j.checked_add(op_items_per_chunk).unwrap())?; + + let left_res = f(left)?; + let right_res = f(right)?; + + this.write_scalar(left_res, &left_dest)?; + this.write_scalar(right_res, &right_dest)?; + } + } + + Ok(()) +} + +/// Converts two 16-bit integer vectors to a single 8-bit integer +/// vector with signed saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packsswb<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i16()?; + let res = i8::try_from(op).unwrap_or(if op < 0 { i8::MIN } else { i8::MAX }); + Ok(Scalar::from_i8(res)) + }) +} + +/// Converts two 16-bit signed integer vectors to a single 8-bit +/// unsigned integer vector with saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packuswb<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i16()?; + let res = u8::try_from(op).unwrap_or(if op < 0 { 0 } else { u8::MAX }); + Ok(Scalar::from_u8(res)) + }) +} + +/// Converts two 32-bit integer vectors to a single 16-bit integer +/// vector with signed saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packssdw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i32()?; + let res = i16::try_from(op).unwrap_or(if op < 0 { i16::MIN } else { i16::MAX }); + Ok(Scalar::from_i16(res)) + }) +} + +/// Converts two 32-bit integer vectors to a single 16-bit integer +/// vector with unsigned saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packusdw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i32()?; + let res = u16::try_from(op).unwrap_or(if op < 0 { 0 } else { u16::MAX }); + Ok(Scalar::from_u16(res)) + }) +} + +/// Negates elements from `left` when the corresponding element in +/// `right` is negative. If an element from `right` is zero, zero +/// is writen to the corresponding output element. +/// In other words, multiplies `left` with `right.signum()`. +fn psign<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + let left = this.read_immediate(&this.project_index(&left, i)?)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_int(dest.layout.size)?; + + let res = this.wrapping_binary_op( + mir::BinOp::Mul, + &left, + &ImmTy::from_int(right.signum(), dest.layout), + )?; + + this.write_immediate(*res, &dest)?; + } + + Ok(()) +} diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index b8c0dfb1c7f02..176088373196f 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -182,7 +182,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: }; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE semantics. + // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 9db30d7ddca21..c9ed751d36c43 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -3,8 +3,8 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, shift_simd_by_scalar, - FloatBinOp, ShiftOp, + bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, packssdw, packsswb, + packuswb, shift_simd_by_scalar, FloatBinOp, ShiftOp, }; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -176,29 +176,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i16x8, dest is i8x16 - assert_eq!(left_len, 8); - assert_eq!(right_len, 8); - assert_eq!(dest_len, 16); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - i8::try_from(left).unwrap_or(if left < 0 { i8::MIN } else { i8::MAX }); - let right_res = - i8::try_from(right).unwrap_or(if right < 0 { i8::MIN } else { i8::MAX }); - - this.write_scalar(Scalar::from_i8(left_res), &left_dest)?; - this.write_scalar(Scalar::from_i8(right_res), &right_dest)?; - } + packsswb(this, left, right, dest)?; } // Used to implement the _mm_packus_epi16 function. // Converts two 16-bit signed integer vectors to a single 8-bit @@ -207,28 +185,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i16x8, dest is u8x16 - assert_eq!(left_len, 8); - assert_eq!(right_len, 8); - assert_eq!(dest_len, 16); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = u8::try_from(left).unwrap_or(if left < 0 { 0 } else { u8::MAX }); - let right_res = - u8::try_from(right).unwrap_or(if right < 0 { 0 } else { u8::MAX }); - - this.write_scalar(Scalar::from_u8(left_res), &left_dest)?; - this.write_scalar(Scalar::from_u8(right_res), &right_dest)?; - } + packuswb(this, left, right, dest)?; } // Used to implement the _mm_packs_epi32 function. // Converts two 32-bit integer vectors to a single 16-bit integer @@ -237,29 +194,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i32x4, dest is i16x8 - assert_eq!(left_len, 4); - assert_eq!(right_len, 4); - assert_eq!(dest_len, 8); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i32()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i32()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - i16::try_from(left).unwrap_or(if left < 0 { i16::MIN } else { i16::MAX }); - let right_res = - i16::try_from(right).unwrap_or(if right < 0 { i16::MIN } else { i16::MAX }); - - this.write_scalar(Scalar::from_i16(left_res), &left_dest)?; - this.write_scalar(Scalar::from_i16(right_res), &right_dest)?; - } + packssdw(this, left, right, dest)?; } // Used to implement _mm_min_sd and _mm_max_sd functions. // Note that the semantics are a bit different from Rust simd_min @@ -420,7 +355,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: }; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE semantics. + // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); @@ -447,7 +382,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let res0 = this.float_to_float_or_int(&right0, dest0.layout)?; this.write_immediate(*res0, &dest0)?; - // Copy remianing from `left` + // Copy remaining from `left` for i in 1..dest_len { this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 16a82eed99b07..19bc27421d348 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -1,7 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use super::{conditional_dot_product, round_all, round_first, test_bits_masked}; +use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked}; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -68,27 +68,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(dest_len, left_len.checked_mul(2).unwrap()); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i32()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i32()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - u16::try_from(left).unwrap_or(if left < 0 { 0 } else { u16::MAX }); - let right_res = - u16::try_from(right).unwrap_or(if right < 0 { 0 } else { u16::MAX }); - - this.write_scalar(Scalar::from_u16(left_res), &left_dest)?; - this.write_scalar(Scalar::from_u16(right_res), &right_dest)?; - } + packusdw(this, left, right, dest)?; } // Used to implement the _mm_dp_ps and _mm_dp_pd functions. // Conditionally multiplies the packed floating-point elements in @@ -176,40 +156,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(left_len, dest_len.checked_mul(2).unwrap()); - - let imm = this.read_scalar(imm)?.to_u8()?; - // Bit 2 of `imm` specifies the offset for indices of `left`. - // The offset is 0 when the bit is 0 or 4 when the bit is 1. - let left_offset = u64::from((imm >> 2) & 1).checked_mul(4).unwrap(); - // Bits 0..=1 of `imm` specify the offset for indices of - // `right` in blocks of 4 elements. - let right_offset = u64::from(imm & 0b11).checked_mul(4).unwrap(); - - for i in 0..dest_len { - let left_offset = left_offset.checked_add(i).unwrap(); - let mut res: u16 = 0; - for j in 0..4 { - let left = this - .read_scalar( - &this.project_index(&left, left_offset.checked_add(j).unwrap())?, - )? - .to_u8()?; - let right = this - .read_scalar( - &this - .project_index(&right, right_offset.checked_add(j).unwrap())?, - )? - .to_u8()?; - res = res.checked_add(left.abs_diff(right).into()).unwrap(); - } - this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, i)?)?; - } + mpsadbw(this, left, right, imm, dest)?; } // Used to implement the _mm_testz_si128, _mm_testc_si128 // and _mm_testnzc_si128 functions. diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index dd5d064b20fe2..4f8e52dbb7d5d 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use super::horizontal_bin_op; +use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -28,20 +28,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(op_len, dest_len); - - for i in 0..dest_len { - let op = this.read_scalar(&this.project_index(&op, i)?)?; - let dest = this.project_index(&dest, i)?; - - // Converting to a host "i128" works since the input is always signed. - let res = op.to_int(dest.layout.size)?.unsigned_abs(); - - this.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?; - } + int_abs(this, op, dest)?; } // Used to implement the _mm_shuffle_epi8 intrinsic. // Shuffles bytes from `left` using `right` as pattern. @@ -136,30 +123,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let dest = this.project_index(&dest, i)?; - - let res = (i32::from(left).checked_mul(right.into()).unwrap() >> 14) - .checked_add(1) - .unwrap() - >> 1; - - // The result of this operation can overflow a signed 16-bit integer. - // When `left` and `right` are -0x8000, the result is 0x8000. - #[allow(clippy::cast_possible_truncation)] - let res = res as i16; - - this.write_scalar(Scalar::from_i16(res), &dest)?; - } + pmulhrsw(this, left, right, dest)?; } // Used to implement the _mm_sign_epi{8,16,32} functions. // Negates elements from `left` when the corresponding element in @@ -170,28 +134,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let dest = this.project_index(&dest, i)?; - let left = this.read_immediate(&this.project_index(&left, i)?)?; - let right = this - .read_scalar(&this.project_index(&right, i)?)? - .to_int(dest.layout.size)?; - - let res = this.wrapping_binary_op( - mir::BinOp::Mul, - &left, - &ImmTy::from_int(right.signum(), dest.layout), - )?; - - this.write_immediate(*res, &dest)?; - } + psign(this, left, right, dest)?; } _ => return Ok(EmulateForeignItemResult::NotSupported), } diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs index e188a1f0c3438..c656a5096445e 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs @@ -8,7 +8,7 @@ use std::mem; pub fn safe(x: &i32, y: &mut Cell) { //~[stack]^ ERROR: protect y.set(1); - let _ = *x; + let _load = *x; } fn main() { diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs index 005ae7e91323c..46ec58810a62d 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::{Coroutine, CoroutineState}, @@ -7,6 +7,7 @@ use std::{ }; fn firstn() -> impl Coroutine { + #[coroutine] static move || { let mut num = 0; let num = &mut num; diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs index f9983f48c6174..f434928680108 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - let _ = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer + let _ref = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer } fn main() { diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 27e5a865069ad..73c3ff1ee0512 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | -LL | let _ = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) +LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs index 13f913454dcdf..f71df9a1c909d 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs @@ -1,3 +1,6 @@ +// Validation stops this too early. +//@compile-flags: -Zmiri-disable-validation + trait T1 { #[allow(dead_code)] fn method1(self: Box); @@ -13,5 +16,5 @@ impl T1 for i32 { fn main() { let r = Box::new(0) as Box; let r2: Box = unsafe { std::mem::transmute(r) }; - r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type + r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected } diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr index 365186bcc4b41..019a55bcdcb1a 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type +error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected --> $DIR/dyn-call-trait-mismatch.rs:LL:CC | LL | r2.method2(); - | ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type + | ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs new file mode 100644 index 0000000000000..dff5a21c4c777 --- /dev/null +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs @@ -0,0 +1,15 @@ +// This upcast is currently forbidden because it involves an invalid value. +// However, if in the future we relax the validity requirements for raw pointer vtables, +// we could consider allowing this again -- the cast itself isn't doing anything wrong, +// only the transmutes needed to set up the testcase are wrong. + +use std::fmt; + +fn main() { + // vtable_mismatch_nop_cast + let ptr: &dyn fmt::Display = &0; + let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; //~ERROR: wrong trait + // Even though the vtable is for the wrong trait, this cast doesn't actually change the needed + // vtable so it should still be allowed -- if we ever allow the line above. + let _ptr2 = ptr as *const dyn fmt::Debug; +} diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr new file mode 100644 index 0000000000000..4165d5ea15d97 --- /dev/null +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` + --> $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + | +LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 982f33b0a3102..1d6b6777032de 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -1,3 +1,6 @@ +// Validation stops this too early. +//@compile-flags: -Zmiri-disable-validation + #![feature(trait_upcasting)] #![allow(incomplete_features)] @@ -57,7 +60,7 @@ impl Baz for i32 { fn main() { let baz: &dyn Baz = &1; - let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; - let _err = baz_fake as &dyn Foo; - //~^ERROR: upcast on a pointer whose vtable does not match its type + let baz_fake: *const dyn Bar = unsafe { std::mem::transmute(baz) }; + let _err = baz_fake as *const dyn Foo; + //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected } diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr index 8bac908b864bc..6a2415cf57e29 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: upcast on a pointer whose vtable does not match its type +error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC | -LL | let _err = baz_fake as &dyn Foo; - | ^^^^^^^^ upcast on a pointer whose vtable does not match its type +LL | let _err = baz_fake as *const dyn Foo; + | ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs index c26cd4cadb539..0b34afc6090a8 100644 --- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs @@ -2,7 +2,7 @@ mod rusti { extern "rust-intrinsic" { - pub fn ctlz_nonzero(x: T) -> T; + pub fn ctlz_nonzero(x: T) -> u32; } } diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs index 25a0501fdd80e..e220411f58544 100644 --- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs @@ -2,7 +2,7 @@ mod rusti { extern "rust-intrinsic" { - pub fn cttz_nonzero(x: T) -> T; + pub fn cttz_nonzero(x: T) -> u32; } } diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs new file mode 100644 index 0000000000000..9b1cefc4b1d3d --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs @@ -0,0 +1,12 @@ +use std::mem; + +// Make sure we notice the mismatch also if the difference is "only" in the generic +// parameters of the trait. + +trait Trait {} +impl Trait for T {} + +fn main() { + let x: &dyn Trait = &0; + let _y: *const dyn Trait = unsafe { mem::transmute(x) }; //~ERROR: wrong trait +} diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr new file mode 100644 index 0000000000000..1219f9f88cf8c --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + --> $DIR/wrong-dyn-trait-generic.rs:LL:CC + | +LL | let _y: *const dyn Trait = unsafe { mem::transmute(x) }; + | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/wrong-dyn-trait-generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs new file mode 100644 index 0000000000000..d6049196f2662 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs @@ -0,0 +1,6 @@ +use std::{fmt, mem}; + +fn main() { + let x: &dyn Send = &0; + let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; //~ERROR: wrong trait +} diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr new file mode 100644 index 0000000000000..e3503323b31a7 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` + --> $DIR/wrong-dyn-trait.rs:LL:CC + | +LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; + | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/wrong-dyn-trait.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/many-seeds/tls-leak.rs b/src/tools/miri/tests/many-seeds/tls-leak.rs new file mode 100644 index 0000000000000..3b2436334395f --- /dev/null +++ b/src/tools/miri/tests/many-seeds/tls-leak.rs @@ -0,0 +1,26 @@ +//! Regression test for . +use std::thread; + +fn with_thread_local1() { + thread_local! { static X: Box = Box::new(0); } + X.with(|_x| {}) +} + +fn with_thread_local2() { + thread_local! { static Y: Box = Box::new(0); } + Y.with(|_y| {}) +} + +fn main() { + // Here we have two threads racing on initializing the thread-local and adding it to the global + // dtor list (on targets that have such a list, i.e., targets without target_thread_local). + let t = thread::spawn(with_thread_local1); + with_thread_local1(); + t.join().unwrap(); + + // Here we have one thread running the destructors racing with another thread initializing a + // thread-local. The second thread adds a destructor that could be picked up by the first. + let t = thread::spawn(|| { /* immediately just run destructors */ }); + with_thread_local2(); // initialize thread-local + t.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs index abb384b0a857c..f710daf527745 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs @@ -213,6 +213,50 @@ fn test_posix_gettimeofday() { assert_eq!(is_error, -1); } +fn test_localtime_r() { + use std::ffi::CStr; + use std::{env, ptr}; + + // Set timezone to GMT. + let key = "TZ"; + env::set_var(key, "GMT"); + + const TIME_SINCE_EPOCH: libc::time_t = 1712475836; + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = libc::tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: std::ptr::null_mut::(), + }; + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + assert_eq!(tm.tm_sec, 56); + assert_eq!(tm.tm_min, 43); + assert_eq!(tm.tm_hour, 7); + assert_eq!(tm.tm_mday, 7); + assert_eq!(tm.tm_mon, 3); + assert_eq!(tm.tm_year, 124); + assert_eq!(tm.tm_wday, 0); + assert_eq!(tm.tm_yday, 97); + assert_eq!(tm.tm_isdst, -1); + assert_eq!(tm.tm_gmtoff, 0); + unsafe { assert_eq!(CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") }; + + // The returned value is the pointer passed in. + assert!(ptr::eq(res, &mut tm)); + + //Remove timezone setting. + env::remove_var(key); +} + fn test_isatty() { // Testing whether our isatty shim returns the right value would require controlling whether // these streams are actually TTYs, which is hard. @@ -365,6 +409,7 @@ fn main() { test_posix_realpath_errors(); test_thread_local_errno(); + test_localtime_r(); test_isatty(); diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs index cbf41d68b5742..8be4bdac7e1bb 100644 --- a/src/tools/miri/tests/pass/adjacent-allocs.rs +++ b/src/tools/miri/tests/pass/adjacent-allocs.rs @@ -30,7 +30,7 @@ fn test1() { // See https://github.com/rust-lang/miri/issues/1866#issuecomment-985770125 { let m = 0u64; - let _ = &m as *const u64; + let _ptr = &m as *const u64; } let iptr = ptr as usize; diff --git a/src/tools/miri/tests/pass/async-drop.rs b/src/tools/miri/tests/pass/async-drop.rs new file mode 100644 index 0000000000000..f16206f3db62d --- /dev/null +++ b/src/tools/miri/tests/pass/async-drop.rs @@ -0,0 +1,191 @@ +//@revisions: stack tree +//@compile-flags: -Zmiri-strict-provenance +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(async_drop, impl_trait_in_assoc_type, noop_waker, async_closure)] +#![allow(incomplete_features, dead_code)] + +// FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests +use core::future::{async_drop_in_place, AsyncDrop, Future}; +use core::hint::black_box; +use core::mem::{self, ManuallyDrop}; +use core::pin::{pin, Pin}; +use core::task::{Context, Poll, Waker}; + +async fn test_async_drop(x: T) { + let mut x = mem::MaybeUninit::new(x); + let dtor = pin!(unsafe { async_drop_in_place(x.as_mut_ptr()) }); + test_idempotency(dtor).await; +} + +fn test_idempotency(mut x: Pin<&mut T>) -> impl Future + '_ +where + T: Future, +{ + core::future::poll_fn(move |cx| { + assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); + assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); + Poll::Ready(()) + }) +} + +fn main() { + let waker = Waker::noop(); + let mut cx = Context::from_waker(&waker); + + let i = 13; + let fut = pin!(async { + test_async_drop(Int(0)).await; + test_async_drop(AsyncInt(0)).await; + test_async_drop([AsyncInt(1), AsyncInt(2)]).await; + test_async_drop((AsyncInt(3), AsyncInt(4))).await; + test_async_drop(5).await; + let j = 42; + test_async_drop(&i).await; + test_async_drop(&j).await; + test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }).await; + test_async_drop(ManuallyDrop::new(AsyncInt(9))).await; + + let foo = AsyncInt(10); + test_async_drop(AsyncReference { foo: &foo }).await; + + let foo = AsyncInt(11); + test_async_drop(|| { + black_box(foo); + let foo = AsyncInt(10); + foo + }) + .await; + + test_async_drop(AsyncEnum::A(AsyncInt(12))).await; + test_async_drop(AsyncEnum::B(SyncInt(13))).await; + + test_async_drop(SyncInt(14)).await; + test_async_drop(SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) }) + .await; + + let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19))); + test_idempotency(async_drop_fut).await; + + let foo = AsyncInt(20); + test_async_drop(async || { + black_box(foo); + let foo = AsyncInt(19); + // Await point there, but this is async closure so it's fine + black_box(core::future::ready(())).await; + foo + }) + .await; + + test_async_drop(AsyncUnion { signed: 21 }).await; + }); + let res = fut.poll(&mut cx); + assert_eq!(res, Poll::Ready(())); +} + +struct AsyncInt(i32); + +impl AsyncDrop for AsyncInt { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncInt::Dropper::poll: {}", self.0); + } + } +} + +struct SyncInt(i32); + +impl Drop for SyncInt { + fn drop(&mut self) { + println!("SyncInt::drop: {}", self.0); + } +} + +struct SyncThenAsync { + i: i32, + a: AsyncInt, + b: SyncInt, + c: AsyncInt, +} + +impl Drop for SyncThenAsync { + fn drop(&mut self) { + println!("SyncThenAsync::drop: {}", self.i); + } +} + +struct AsyncReference<'a> { + foo: &'a AsyncInt, +} + +impl AsyncDrop for AsyncReference<'_> { + type Dropper<'a> = impl Future where Self: 'a; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncReference::Dropper::poll: {}", self.foo.0); + } + } +} + +struct Int(i32); + +struct AsyncStruct { + i: i32, + a: AsyncInt, + b: AsyncInt, +} + +impl AsyncDrop for AsyncStruct { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncStruct::Dropper::poll: {}", self.i); + } + } +} + +enum AsyncEnum { + A(AsyncInt), + B(SyncInt), +} + +impl AsyncDrop for AsyncEnum { + type Dropper<'a> = impl Future; + + fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + let new_self = match &*self { + AsyncEnum::A(foo) => { + println!("AsyncEnum(A)::Dropper::poll: {}", foo.0); + AsyncEnum::B(SyncInt(foo.0)) + } + AsyncEnum::B(foo) => { + println!("AsyncEnum(B)::Dropper::poll: {}", foo.0); + AsyncEnum::A(AsyncInt(foo.0)) + } + }; + mem::forget(mem::replace(&mut *self, new_self)); + } + } +} + +// FIXME(zetanumbers): Disallow types with `AsyncDrop` in unions +union AsyncUnion { + signed: i32, + unsigned: u32, +} + +impl AsyncDrop for AsyncUnion { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncUnion::Dropper::poll: {}, {}", unsafe { self.signed }, unsafe { + self.unsigned + }); + } + } +} diff --git a/src/tools/miri/tests/pass/async-drop.stack.stdout b/src/tools/miri/tests/pass/async-drop.stack.stdout new file mode 100644 index 0000000000000..9cae4331caf92 --- /dev/null +++ b/src/tools/miri/tests/pass/async-drop.stack.stdout @@ -0,0 +1,22 @@ +AsyncInt::Dropper::poll: 0 +AsyncInt::Dropper::poll: 1 +AsyncInt::Dropper::poll: 2 +AsyncInt::Dropper::poll: 3 +AsyncInt::Dropper::poll: 4 +AsyncStruct::Dropper::poll: 6 +AsyncInt::Dropper::poll: 7 +AsyncInt::Dropper::poll: 8 +AsyncReference::Dropper::poll: 10 +AsyncInt::Dropper::poll: 11 +AsyncEnum(A)::Dropper::poll: 12 +SyncInt::drop: 12 +AsyncEnum(B)::Dropper::poll: 13 +AsyncInt::Dropper::poll: 13 +SyncInt::drop: 14 +SyncThenAsync::drop: 15 +AsyncInt::Dropper::poll: 16 +SyncInt::drop: 17 +AsyncInt::Dropper::poll: 18 +AsyncInt::Dropper::poll: 19 +AsyncInt::Dropper::poll: 20 +AsyncUnion::Dropper::poll: 21, 21 diff --git a/src/tools/miri/tests/pass/async-drop.tree.stdout b/src/tools/miri/tests/pass/async-drop.tree.stdout new file mode 100644 index 0000000000000..9cae4331caf92 --- /dev/null +++ b/src/tools/miri/tests/pass/async-drop.tree.stdout @@ -0,0 +1,22 @@ +AsyncInt::Dropper::poll: 0 +AsyncInt::Dropper::poll: 1 +AsyncInt::Dropper::poll: 2 +AsyncInt::Dropper::poll: 3 +AsyncInt::Dropper::poll: 4 +AsyncStruct::Dropper::poll: 6 +AsyncInt::Dropper::poll: 7 +AsyncInt::Dropper::poll: 8 +AsyncReference::Dropper::poll: 10 +AsyncInt::Dropper::poll: 11 +AsyncEnum(A)::Dropper::poll: 12 +SyncInt::drop: 12 +AsyncEnum(B)::Dropper::poll: 13 +AsyncInt::Dropper::poll: 13 +SyncInt::drop: 14 +SyncThenAsync::drop: 15 +AsyncInt::Dropper::poll: 16 +SyncInt::drop: 17 +AsyncInt::Dropper::poll: 18 +AsyncInt::Dropper::poll: 19 +AsyncInt::Dropper::poll: 20 +AsyncUnion::Dropper::poll: 21, 21 diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout index c9cab268168c9..e6644b4453fa5 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ $DIR/backtrace-api-v0.rs:24:14 (func_d) -$DIR/backtrace-api-v0.rs:20:5 (func_c) +$DIR/backtrace-api-v0.rs:14:9 (func_c) $DIR/backtrace-api-v0.rs:9:5 (func_b::) $DIR/backtrace-api-v0.rs:5:5 (func_a) $DIR/backtrace-api-v0.rs:29:18 (main) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout index e145c167e880e..11efd2f0752d9 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ $DIR/backtrace-api-v1.rs:27:9 (func_d) -$DIR/backtrace-api-v1.rs:20:5 (func_c) +$DIR/backtrace-api-v1.rs:14:9 (func_c) $DIR/backtrace-api-v1.rs:9:5 (func_b::) $DIR/backtrace-api-v1.rs:5:5 (func_a) $DIR/backtrace-api-v1.rs:34:18 (main) diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index 2491bda0917d3..adbf5df62cc5d 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -25,7 +25,7 @@ impl Foo for u32 { impl Bar for () {} unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo + 'a)) -> u32 { - let foo_e: *const dyn Foo = t as *const _; + let foo_e: *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs index 6c14f0b679ce8..727c67ebfb574 100644 --- a/src/tools/miri/tests/pass/const-addrs.rs +++ b/src/tools/miri/tests/pass/const-addrs.rs @@ -4,7 +4,7 @@ // deallocated. // In Miri we explicitly store previously-assigned AllocIds for each const and ensure // that we only hand out a finite number of AllocIds per const. -// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same +// MIR inlining will put every evaluation of the const we're repeatedly evaluating into the same // stack frame, breaking this test. //@compile-flags: -Zinline-mir=no #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs index 7e1f64df04d4c..7822c136d91b6 100644 --- a/src/tools/miri/tests/pass/coroutine.rs +++ b/src/tools/miri/tests/pass/coroutine.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(coroutines, coroutine_trait, never_type)] +#![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)] use std::fmt::Debug; use std::mem::ManuallyDrop; @@ -43,94 +43,144 @@ fn basic() { panic!() } - finish(1, false, || yield 1); + finish( + 1, + false, + #[coroutine] + || yield 1, + ); - finish(3, false, || { - let mut x = 0; - yield 1; - x += 1; - yield 1; - x += 1; - yield 1; - assert_eq!(x, 2); - }); + finish( + 3, + false, + #[coroutine] + || { + let mut x = 0; + yield 1; + x += 1; + yield 1; + x += 1; + yield 1; + assert_eq!(x, 2); + }, + ); - finish(7 * 8 / 2, false, || { - for i in 0..8 { - yield i; - } - }); + finish( + 7 * 8 / 2, + false, + #[coroutine] + || { + for i in 0..8 { + yield i; + } + }, + ); - finish(1, false, || { - if true { - yield 1; - } else { - } - }); + finish( + 1, + false, + #[coroutine] + || { + if true { + yield 1; + } else { + } + }, + ); - finish(1, false, || { - if false { - } else { - yield 1; - } - }); + finish( + 1, + false, + #[coroutine] + || { + if false { + } else { + yield 1; + } + }, + ); - finish(2, false, || { - if { - yield 1; - false - } { + finish( + 2, + false, + #[coroutine] + || { + if { + yield 1; + false + } { + yield 1; + panic!() + } yield 1; - panic!() - } - yield 1; - }); + }, + ); // also test self-referential coroutines assert_eq!( - finish(5, true, static || { - let mut x = 5; - let y = &mut x; - *y = 5; - yield *y; - *y = 10; - x - }), + finish( + 5, + true, + #[coroutine] + static || { + let mut x = 5; + let y = &mut x; + *y = 5; + yield *y; + *y = 10; + x + } + ), 10 ); assert_eq!( - finish(5, true, || { - let mut x = Box::new(5); - let y = &mut *x; - *y = 5; - yield *y; - *y = 10; - *x - }), + finish( + 5, + true, + #[coroutine] + || { + let mut x = Box::new(5); + let y = &mut *x; + *y = 5; + yield *y; + *y = 10; + *x + } + ), 10 ); let b = true; - finish(1, false, || { - yield 1; - if b { - return; - } - #[allow(unused)] - let x = never(); - #[allow(unreachable_code)] - yield 2; - drop(x); - }); - - finish(3, false, || { - yield 1; - #[allow(unreachable_code)] - let _x: (String, !) = (String::new(), { + finish( + 1, + false, + #[coroutine] + || { + yield 1; + if b { + return; + } + #[allow(unused)] + let x = never(); + #[allow(unreachable_code)] yield 2; - return; - }); - }); + drop(x); + }, + ); + + finish( + 3, + false, + #[coroutine] + || { + yield 1; + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), { + yield 2; + return; + }); + }, + ); } fn smoke_resume_arg() { @@ -172,7 +222,8 @@ fn smoke_resume_arg() { } drain( - &mut |mut b| { + &mut #[coroutine] + |mut b| { while b != 0 { b = yield (b + 1); } @@ -181,21 +232,35 @@ fn smoke_resume_arg() { vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], ); - expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + expect_drops(2, || { + drain( + &mut #[coroutine] + |a| yield a, + vec![(DropMe, Yielded(DropMe))], + ) + }); expect_drops(6, || { drain( - &mut |a| yield yield a, + &mut #[coroutine] + |a| yield yield a, vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], ) }); #[allow(unreachable_code)] - expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + expect_drops(2, || { + drain( + &mut #[coroutine] + |a| yield return a, + vec![(DropMe, Complete(DropMe))], + ) + }); expect_drops(2, || { drain( - &mut |a: DropMe| { + &mut #[coroutine] + |a: DropMe| { if false { yield () } else { a } }, vec![(DropMe, Complete(DropMe))], @@ -205,7 +270,8 @@ fn smoke_resume_arg() { expect_drops(4, || { drain( #[allow(unused_assignments, unused_variables)] - &mut |mut a: DropMe| { + &mut #[coroutine] + |mut a: DropMe| { a = yield; a = yield; a = yield; @@ -228,7 +294,8 @@ fn uninit_fields() { } fn run(x: bool, y: bool) { - let mut c = || { + let mut c = #[coroutine] + || { if x { let _a: T; if y { diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 529b9c471d426..ff995f38196fa 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -1,24 +1,26 @@ #![feature(trait_upcasting)] #![allow(incomplete_features)] +use std::fmt; + fn main() { basic(); diamond(); struct_(); replace_vptr(); - vtable_mismatch_nop_cast(); + vtable_nop_cast(); } -fn vtable_mismatch_nop_cast() { - let ptr: &dyn std::fmt::Display = &0; - // Even though the vtable is for the wrong trait, this cast doesn't actually change the needed - // vtable so it should still be allowed. - let ptr: *const (dyn std::fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; - let _ptr2 = ptr as *const dyn std::fmt::Debug; +fn vtable_nop_cast() { + let ptr: &dyn fmt::Debug = &0; + // We transmute things around, but the principal trait does not change, so this is allowed. + let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; + // This cast is a NOP and should be allowed. + let _ptr2 = ptr as *const dyn fmt::Debug; } fn basic() { - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } @@ -67,7 +69,7 @@ fn basic() { } let baz: &dyn Baz = &1; - let _: &dyn std::fmt::Debug = baz; + let _up: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -77,7 +79,7 @@ fn basic() { assert_eq!(baz.w(), 21); let bar: &dyn Bar = baz; - let _: &dyn std::fmt::Debug = bar; + let _up: &dyn fmt::Debug = bar; assert_eq!(*bar, 1); assert_eq!(bar.a(), 100); assert_eq!(bar.b(), 200); @@ -86,14 +88,14 @@ fn basic() { assert_eq!(bar.w(), 21); let foo: &dyn Foo = baz; - let _: &dyn std::fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); assert_eq!(foo.y(), 12); let foo: &dyn Foo = bar; - let _: &dyn std::fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); @@ -101,7 +103,7 @@ fn basic() { } fn diamond() { - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } @@ -166,7 +168,7 @@ fn diamond() { } let baz: &dyn Baz = &1; - let _: &dyn std::fmt::Debug = baz; + let _up: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -178,7 +180,7 @@ fn diamond() { assert_eq!(baz.v(), 31); let bar1: &dyn Bar1 = baz; - let _: &dyn std::fmt::Debug = bar1; + let _up: &dyn fmt::Debug = bar1; assert_eq!(*bar1, 1); assert_eq!(bar1.a(), 100); assert_eq!(bar1.b(), 200); @@ -187,7 +189,7 @@ fn diamond() { assert_eq!(bar1.w(), 21); let bar2: &dyn Bar2 = baz; - let _: &dyn std::fmt::Debug = bar2; + let _up: &dyn fmt::Debug = bar2; assert_eq!(*bar2, 1); assert_eq!(bar2.a(), 100); assert_eq!(bar2.c(), 300); @@ -196,17 +198,17 @@ fn diamond() { assert_eq!(bar2.v(), 31); let foo: &dyn Foo = baz; - let _: &dyn std::fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar1; - let _: &dyn std::fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar2; - let _: &dyn std::fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); } @@ -215,7 +217,7 @@ fn struct_() { use std::rc::Rc; use std::sync::Arc; - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs new file mode 100644 index 0000000000000..80d125bb85650 --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs @@ -0,0 +1,1613 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+avx2 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::mem::transmute; + +fn main() { + assert!(is_x86_feature_detected!("avx2")); + + unsafe { + test_avx2(); + } +} + +#[target_feature(enable = "avx2")] +unsafe fn test_avx2() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86/avx2.rs + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi32() { + #[rustfmt::skip] + let a = _mm256_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi32(a); + #[rustfmt::skip] + let e = _mm256_setr_epi32( + 0, 1, 1, i32::MAX, + i32::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi16() { + #[rustfmt::skip] + let a = _mm256_setr_epi16( + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i16::MAX, i16::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi16(a); + #[rustfmt::skip] + let e = _mm256_setr_epi16( + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i16::MAX, i16::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi8() { + #[rustfmt::skip] + let a = _mm256_setr_epi8( + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i8::MAX, i8::MIN, 100, -100, -32, + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i8::MAX, i8::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi8(a); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i8::MAX, i8::MAX.wrapping_add(1), 100, 100, 32, + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i8::MAX, i8::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadd_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_hadd_epi16(a, b); + let e = _mm256_setr_epi16(4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi16( + i16::MAX, + 1, + i16::MAX, + 2, + i16::MAX, + 3, + i16::MAX, + 4, + i16::MAX, + 5, + i16::MAX, + 6, + i16::MAX, + 7, + i16::MAX, + 8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + -1, + i16::MIN, + -2, + i16::MIN, + -3, + i16::MIN, + -4, + i16::MIN, + -5, + i16::MIN, + -6, + i16::MIN, + -7, + i16::MIN, + -8, + ); + let expected = _mm256_setr_epi16( + i16::MIN, + i16::MIN + 1, + i16::MIN + 2, + i16::MIN + 3, + i16::MAX, + i16::MAX - 1, + i16::MAX - 2, + i16::MAX - 3, + i16::MIN + 4, + i16::MIN + 5, + i16::MIN + 6, + i16::MIN + 7, + i16::MAX - 4, + i16::MAX - 5, + i16::MAX - 6, + i16::MAX - 7, + ); + let r = _mm256_hadd_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadd_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadd_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_hadd_epi32(a, b); + let e = _mm256_setr_epi32(4, 4, 8, 8, 4, 4, 8, 8); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi32(i32::MAX, 1, i32::MAX, 2, i32::MAX, 3, i32::MAX, 4); + let b = _mm256_setr_epi32(i32::MIN, -1, i32::MIN, -2, i32::MIN, -3, i32::MIN, -4); + let expected = _mm256_setr_epi32( + i32::MIN, + i32::MIN + 1, + i32::MAX, + i32::MAX - 1, + i32::MIN + 2, + i32::MIN + 3, + i32::MAX - 2, + i32::MAX - 3, + ); + let r = _mm256_hadd_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadd_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadds_epi16() { + let a = _mm256_set1_epi16(2); + let a = _mm256_insert_epi16::<0>(a, 0x7fff); + let a = _mm256_insert_epi16::<1>(a, 1); + let b = _mm256_set1_epi16(4); + let r = _mm256_hadds_epi16(a, b); + let e = _mm256_setr_epi16(0x7FFF, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8); + assert_eq_m256i(r, e); + + // Test saturating on overflow + let a = _mm256_setr_epi16( + i16::MAX, + 1, + i16::MAX, + 2, + i16::MAX, + 3, + i16::MAX, + 4, + i16::MAX, + 5, + i16::MAX, + 6, + i16::MAX, + 7, + i16::MAX, + 8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + -1, + i16::MIN, + -2, + i16::MIN, + -3, + i16::MIN, + -4, + i16::MIN, + -5, + i16::MIN, + -6, + i16::MIN, + -7, + i16::MIN, + -8, + ); + let expected = _mm256_setr_epi16( + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + ); + let r = _mm256_hadds_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadds_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsub_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_hsub_epi16(a, b); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi16( + i16::MAX, + -1, + i16::MAX, + -2, + i16::MAX, + -3, + i16::MAX, + -4, + i16::MAX, + -5, + i16::MAX, + -6, + i16::MAX, + -7, + i16::MAX, + -8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + 1, + i16::MIN, + 2, + i16::MIN, + 3, + i16::MIN, + 4, + i16::MIN, + 5, + i16::MIN, + 6, + i16::MIN, + 7, + i16::MIN, + 8, + ); + let expected = _mm256_setr_epi16( + i16::MIN, + i16::MIN + 1, + i16::MIN + 2, + i16::MIN + 3, + i16::MAX, + i16::MAX - 1, + i16::MAX - 2, + i16::MAX - 3, + i16::MIN + 4, + i16::MIN + 5, + i16::MIN + 6, + i16::MIN + 7, + i16::MAX - 4, + i16::MAX - 5, + i16::MAX - 6, + i16::MAX - 7, + ); + let r = _mm256_hsub_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsub_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsub_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_hsub_epi32(a, b); + let e = _mm256_set1_epi32(0); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi32(i32::MAX, -1, i32::MAX, -2, i32::MAX, -3, i32::MAX, -4); + let b = _mm256_setr_epi32(i32::MIN, 1, i32::MIN, 2, i32::MIN, 3, i32::MIN, 4); + let expected = _mm256_setr_epi32( + i32::MIN, + i32::MIN + 1, + i32::MAX, + i32::MAX - 1, + i32::MIN + 2, + i32::MIN + 3, + i32::MAX - 2, + i32::MAX - 3, + ); + let r = _mm256_hsub_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsub_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsubs_epi16() { + let a = _mm256_set1_epi16(2); + let a = _mm256_insert_epi16::<0>(a, 0x7fff); + let a = _mm256_insert_epi16::<1>(a, -1); + let b = _mm256_set1_epi16(4); + let r = _mm256_hsubs_epi16(a, b); + let e = _mm256_insert_epi16::<0>(_mm256_set1_epi16(0), 0x7FFF); + assert_eq_m256i(r, e); + + // Test saturating on overflow + let a = _mm256_setr_epi16( + i16::MAX, + -1, + i16::MAX, + -2, + i16::MAX, + -3, + i16::MAX, + -4, + i16::MAX, + -5, + i16::MAX, + -6, + i16::MAX, + -7, + i16::MAX, + -8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + 1, + i16::MIN, + 2, + i16::MIN, + 3, + i16::MIN, + 4, + i16::MIN, + 5, + i16::MIN, + 6, + i16::MIN, + 7, + i16::MIN, + 8, + ); + let expected = _mm256_setr_epi16( + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + ); + let r = _mm256_hsubs_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsubs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_i32gather_epi32::<4>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 32, 48)); + } + test_mm_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_mask_i32gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm_setr_epi32(-1, -1, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 64, 256)); + } + test_mm_mask_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = + _mm256_i32gather_epi32::<4>(arr.as_ptr(), _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + } + test_mm256_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_mask_i32gather_epi32::<4>( + _mm256_set1_epi32(256), + arr.as_ptr(), + _mm256_setr_epi32(0, 16, 64, 96, 0, 0, 0, 0), + _mm256_setr_epi32(-1, -1, -1, 0, 0, 0, 0, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 64, 256, 256, 256, 256, 256)); + } + test_mm256_mask_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_i32gather_ps::<4>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 32.0, 48.0)); + } + test_mm_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_mask_i32gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm_setr_ps(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 64.0, 256.0)); + } + test_mm_mask_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = + _mm256_i32gather_ps::<4>(arr.as_ptr(), _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + assert_eq_m256(r, _mm256_setr_ps(0.0, 16.0, 32.0, 48.0, 1.0, 2.0, 3.0, 4.0)); + } + test_mm256_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_mask_i32gather_ps::<4>( + _mm256_set1_ps(256.0), + arr.as_ptr(), + _mm256_setr_epi32(0, 16, 64, 96, 0, 0, 0, 0), + _mm256_setr_ps(-1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0), + ); + assert_eq_m256(r, _mm256_setr_ps(0.0, 16.0, 64.0, 256.0, 256.0, 256.0, 256.0, 256.0)); + } + test_mm256_mask_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_i32gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 0, 0)); + assert_eq_m128i(r, _mm_setr_epi64x(0, 16)); + } + test_mm_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_mask_i32gather_epi64::<8>( + _mm_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi32(16, 16, 16, 16), + _mm_setr_epi64x(-1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi64x(16, 256)); + } + test_mm_mask_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_i32gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 32, 48)); + } + test_mm256_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_mask_i32gather_epi64::<8>( + _mm256_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm256_setr_epi64x(-1, -1, -1, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 64, 256)); + } + test_mm256_mask_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_i32gather_pd::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 0, 0)); + assert_eq_m128d(r, _mm_setr_pd(0.0, 16.0)); + } + test_mm_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_mask_i32gather_pd::<8>( + _mm_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi32(16, 16, 16, 16), + _mm_setr_pd(-1.0, 0.0), + ); + assert_eq_m128d(r, _mm_setr_pd(16.0, 256.0)); + } + test_mm_mask_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_i32gather_pd::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_mask_i32gather_pd::<8>( + _mm256_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm256_setr_pd(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_i64gather_epi32::<4>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 0, 0)); + } + test_mm_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_mask_i64gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm_setr_epi64x(0, 16), + _mm_setr_epi32(-1, 0, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 256, 0, 0)); + } + test_mm_mask_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_i64gather_epi32::<4>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 32, 48)); + } + test_mm256_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_mask_i64gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm_setr_epi32(-1, -1, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 64, 256)); + } + test_mm256_mask_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_i64gather_ps::<4>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 0.0, 0.0)); + } + test_mm_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_mask_i64gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm_setr_epi64x(0, 16), + _mm_setr_ps(-1.0, 0.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 256.0, 0.0, 0.0)); + } + test_mm_mask_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_i64gather_ps::<4>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_mask_i64gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm_setr_ps(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_i64gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128i(r, _mm_setr_epi64x(0, 16)); + } + test_mm_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_mask_i64gather_epi64::<8>( + _mm_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi64x(16, 16), + _mm_setr_epi64x(-1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi64x(16, 256)); + } + test_mm_mask_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_i64gather_epi64::<8>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 32, 48)); + } + test_mm256_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_mask_i64gather_epi64::<8>( + _mm256_set1_epi64x(256), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm256_setr_epi64x(-1, -1, -1, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 64, 256)); + } + test_mm256_mask_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_i64gather_pd::<8>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128d(r, _mm_setr_pd(0.0, 16.0)); + } + test_mm_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_mask_i64gather_pd::<8>( + _mm_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi64x(16, 16), + _mm_setr_pd(-1.0, 0.0), + ); + assert_eq_m128d(r, _mm_setr_pd(16.0, 256.0)); + } + test_mm_mask_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_i64gather_pd::<8>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_mask_i64gather_pd::<8>( + _mm256_set1_pd(256.0), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm256_setr_pd(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_madd_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_madd_epi16(a, b); + let e = _mm256_set1_epi32(16); + assert_eq_m256i(r, e); + } + test_mm256_madd_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maddubs_epi16() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(4); + let r = _mm256_maddubs_epi16(a, b); + let e = _mm256_set1_epi16(16); + assert_eq_m256i(r, e); + } + test_mm256_maddubs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskload_epi32() { + let nums = [1, 2, 3, 4]; + let a = &nums as *const i32; + let mask = _mm_setr_epi32(-1, 0, 0, -1); + let r = _mm_maskload_epi32(a, mask); + let e = _mm_setr_epi32(1, 0, 0, 4); + assert_eq_m128i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i32, 2, 3, 4]); + let mask = _mm_setr_epi32(0, !0, 0, !0); + let r = _mm_maskload_epi32(a.as_ptr().cast(), mask); + let e = _mm_setr_epi32(0, 2, 0, 4); + assert_eq_m128i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i32]; + let mask = _mm_setr_epi32(!0, 0, 0, 0); + let r = _mm_maskload_epi32(a.as_ptr(), mask); + let e = _mm_setr_epi32(2, 0, 0, 0); + assert_eq_m128i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i32]; + let mask = _mm_setr_epi32(0, 0, 0, !0); + let r = _mm_maskload_epi32(a.as_ptr().wrapping_sub(3), mask); + let e = _mm_setr_epi32(0, 0, 0, 2); + assert_eq_m128i(r, e); + } + test_mm_maskload_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskload_epi32() { + let nums = [1, 2, 3, 4, 5, 6, 7, 8]; + let a = &nums as *const i32; + let mask = _mm256_setr_epi32(-1, 0, 0, -1, 0, -1, -1, 0); + let r = _mm256_maskload_epi32(a, mask); + let e = _mm256_setr_epi32(1, 0, 0, 4, 0, 6, 7, 0); + assert_eq_m256i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i32, 2, 3, 4, 5, 6, 7, 8]); + let mask = _mm256_setr_epi32(0, !0, 0, !0, 0, !0, 0, !0); + let r = _mm256_maskload_epi32(a.as_ptr().cast(), mask); + let e = _mm256_setr_epi32(0, 2, 0, 4, 0, 6, 0, 8); + assert_eq_m256i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i32]; + let mask = _mm256_setr_epi32(!0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm256_maskload_epi32(a.as_ptr(), mask); + let e = _mm256_setr_epi32(2, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i32]; + let mask = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, !0); + let r = _mm256_maskload_epi32(a.as_ptr().wrapping_sub(7), mask); + let e = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 2); + assert_eq_m256i(r, e); + } + test_mm256_maskload_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskload_epi64() { + let nums = [1_i64, 2_i64]; + let a = &nums as *const i64; + let mask = _mm_setr_epi64x(0, -1); + let r = _mm_maskload_epi64(a, mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i64, 2]); + let mask = _mm_setr_epi64x(0, !0); + let r = _mm_maskload_epi64(a.as_ptr().cast(), mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i64]; + let mask = _mm_setr_epi64x(!0, 0); + let r = _mm_maskload_epi64(a.as_ptr(), mask); + let e = _mm_setr_epi64x(2, 0); + assert_eq_m128i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i64]; + let mask = _mm_setr_epi64x(0, !0); + let r = _mm_maskload_epi64(a.as_ptr().wrapping_sub(1), mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + } + test_mm_maskload_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskload_epi64() { + let nums = [1_i64, 2_i64, 3_i64, 4_i64]; + let a = &nums as *const i64; + let mask = _mm256_setr_epi64x(0, -1, -1, 0); + let r = _mm256_maskload_epi64(a, mask); + let e = _mm256_setr_epi64x(0, 2, 3, 0); + assert_eq_m256i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i64, 2, 3, 4]); + let mask = _mm256_setr_epi64x(0, !0, 0, !0); + let r = _mm256_maskload_epi64(a.as_ptr().cast(), mask); + let e = _mm256_setr_epi64x(0, 2, 0, 4); + assert_eq_m256i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i64]; + let mask = _mm256_setr_epi64x(!0, 0, 0, 0); + let r = _mm256_maskload_epi64(a.as_ptr(), mask); + let e = _mm256_setr_epi64x(2, 0, 0, 0); + assert_eq_m256i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i64]; + let mask = _mm256_setr_epi64x(0, 0, 0, !0); + let r = _mm256_maskload_epi64(a.as_ptr().wrapping_sub(3), mask); + let e = _mm256_setr_epi64x(0, 0, 0, 2); + assert_eq_m256i(r, e); + } + test_mm256_maskload_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskstore_epi32() { + let a = _mm_setr_epi32(1, 2, 3, 4); + let mut arr = [-1, -1, -1, -1]; + let mask = _mm_setr_epi32(-1, 0, 0, -1); + _mm_maskstore_epi32(arr.as_mut_ptr(), mask, a); + let e = [1, -1, -1, 4]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i32; 4]); + let mask = _mm_setr_epi32(0, !0, 0, !0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr().cast(), mask, a); + let e = [0i32, 2, 0, 4]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i32]; + let mask = _mm_setr_epi32(!0, 0, 0, 0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr(), mask, a); + let e = [1i32]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i32]; + let mask = _mm_setr_epi32(0, 0, 0, !0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr().wrapping_sub(3), mask, a); + let e = [4i32]; + assert_eq!(r, e); + } + test_mm_maskstore_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskstore_epi32() { + let a = _mm256_setr_epi32(1, 0x6d726f, 3, 42, 0x777161, 6, 7, 8); + let mut arr = [-1, -1, -1, 0x776173, -1, 0x68657265, -1, -1]; + let mask = _mm256_setr_epi32(-1, 0, 0, -1, 0, -1, -1, 0); + _mm256_maskstore_epi32(arr.as_mut_ptr(), mask, a); + let e = [1, -1, -1, 42, -1, 6, 7, -1]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i32; 8]); + let mask = _mm256_setr_epi32(0, !0, 0, !0, 0, !0, 0, !0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr().cast(), mask, a); + let e = [0i32, 2, 0, 4, 0, 6, 0, 8]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i32]; + let mask = _mm256_setr_epi32(!0, 0, 0, 0, 0, 0, 0, 0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr(), mask, a); + let e = [1i32]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i32]; + let mask = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, !0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr().wrapping_sub(7), mask, a); + let e = [8i32]; + assert_eq!(r, e); + } + test_mm256_maskstore_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskstore_epi64() { + let a = _mm_setr_epi64x(1_i64, 2_i64); + let mut arr = [-1_i64, -1_i64]; + let mask = _mm_setr_epi64x(0, -1); + _mm_maskstore_epi64(arr.as_mut_ptr(), mask, a); + let e = [-1, 2]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i64; 2]); + let mask = _mm_setr_epi64x(0, !0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr().cast(), mask, a); + let e = [0i64, 2]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i64]; + let mask = _mm_setr_epi64x(!0, 0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr(), mask, a); + let e = [1i64]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i64]; + let mask = _mm_setr_epi64x(0, !0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr().wrapping_sub(1), mask, a); + let e = [2i64]; + assert_eq!(r, e); + } + test_mm_maskstore_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskstore_epi64() { + let a = _mm256_setr_epi64x(1_i64, 2_i64, 3_i64, 4_i64); + let mut arr = [-1_i64, -1_i64, -1_i64, -1_i64]; + let mask = _mm256_setr_epi64x(0, -1, -1, 0); + _mm256_maskstore_epi64(arr.as_mut_ptr(), mask, a); + let e = [-1, 2, 3, -1]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i64; 4]); + let mask = _mm256_setr_epi64x(0, !0, 0, !0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr().cast(), mask, a); + let e = [0i64, 2, 0, 4]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i64]; + let mask = _mm256_setr_epi64x(!0, 0, 0, 0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr(), mask, a); + let e = [1i64]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i64]; + let mask = _mm256_setr_epi64x(0, 0, 0, !0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr().wrapping_sub(3), mask, a); + let e = [4i64]; + assert_eq!(r, e); + } + test_mm256_maskstore_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mpsadbw_epu8() { + let a = _mm256_setr_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 16, + 18, 20, 22, 24, 26, 28, 30, + ); + + let r = _mm256_mpsadbw_epu8::<0b000>(a, a); + let e = _mm256_setr_epi16(0, 4, 8, 12, 16, 20, 24, 28, 0, 8, 16, 24, 32, 40, 48, 56); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b001>(a, a); + let e = _mm256_setr_epi16(16, 12, 8, 4, 0, 4, 8, 12, 32, 24, 16, 8, 0, 8, 16, 24); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b100>(a, a); + let e = _mm256_setr_epi16(16, 20, 24, 28, 32, 36, 40, 44, 32, 40, 48, 56, 64, 72, 80, 88); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b101>(a, a); + let e = _mm256_setr_epi16(0, 4, 8, 12, 16, 20, 24, 28, 0, 8, 16, 24, 32, 40, 48, 56); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b111>(a, a); + let e = _mm256_setr_epi16(32, 28, 24, 20, 16, 12, 8, 4, 64, 56, 48, 40, 32, 24, 16, 8); + assert_eq_m256i(r, e); + } + test_mm256_mpsadbw_epu8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mulhrs_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_mullo_epi16(a, b); + let e = _mm256_set1_epi16(8); + assert_eq_m256i(r, e); + } + test_mm256_mulhrs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packs_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_packs_epi16(a, b); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + ); + + assert_eq_m256i(r, e); + } + test_mm256_packs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packs_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_packs_epi32(a, b); + let e = _mm256_setr_epi16(2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 4, 4); + + assert_eq_m256i(r, e); + } + test_mm256_packs_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packus_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_packus_epi16(a, b); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + ); + + assert_eq_m256i(r, e); + } + test_mm256_packus_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packus_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_packus_epi32(a, b); + let e = _mm256_setr_epi16(2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 4, 4); + + assert_eq_m256i(r, e); + } + test_mm256_packus_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permutevar8x32_epi32() { + let a = _mm256_setr_epi32(100, 200, 300, 400, 500, 600, 700, 800); + let b = _mm256_setr_epi32(5, 0, 5, 1, 7, 6, 3, 4); + let expected = _mm256_setr_epi32(600, 100, 600, 200, 800, 700, 400, 500); + let r = _mm256_permutevar8x32_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_permutevar8x32_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permute2x128_si256() { + let a = _mm256_setr_epi64x(100, 200, 500, 600); + let b = _mm256_setr_epi64x(300, 400, 700, 800); + let r = _mm256_permute2x128_si256::<0b00_01_00_11>(a, b); + let e = _mm256_setr_epi64x(700, 800, 500, 600); + assert_eq_m256i(r, e); + } + test_mm256_permute2x128_si256(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permutevar8x32_ps() { + let a = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); + let b = _mm256_setr_epi32(5, 0, 5, 1, 7, 6, 3, 4); + let r = _mm256_permutevar8x32_ps(a, b); + let e = _mm256_setr_ps(6., 1., 6., 2., 8., 7., 4., 5.); + assert_eq_m256(r, e); + } + test_mm256_permutevar8x32_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sad_epu8() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(4); + let r = _mm256_sad_epu8(a, b); + let e = _mm256_set1_epi64x(16); + assert_eq_m256i(r, e); + } + test_mm256_sad_epu8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm256_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ); + #[rustfmt::skip] + let b = _mm256_setr_epi8( + 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, + 12, 5, 5, 10, 4, 1, 8, 0, + 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, + 12, 5, 5, 10, 4, 1, 8, 0, + ); + #[rustfmt::skip] + let expected = _mm256_setr_epi8( + 5, 0, 5, 4, 9, 13, 7, 4, + 13, 6, 6, 11, 5, 2, 9, 1, + 21, 0, 21, 20, 25, 29, 23, 20, + 29, 22, 22, 27, 21, 18, 25, 17, + ); + let r = _mm256_shuffle_epi8(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_shuffle_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(-1); + let r = _mm256_sign_epi16(a, b); + let e = _mm256_set1_epi16(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(-1); + let r = _mm256_sign_epi32(a, b); + let e = _mm256_set1_epi32(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi8() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(-1); + let r = _mm256_sign_epi8(a, b); + let e = _mm256_set1_epi8(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x880, -0x880, 0x990, -0x990, 0xAA0, -0xAA0, 0xBB0, -0xBB0, 0xCC0, -0xCC0, 0xDD0, + -0xDD0, 0xEE0, -0xEE0, 0xFF0, -0xFF0, + ), + ); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + } + test_mm256_sll_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32( + 0xCCCC0, -0xCCCC0, 0xDDDD0, -0xDDDD0, 0xEEEE0, -0xEEEE0, 0xFFFF0, -0xFFFF0, + ), + ); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + } + test_mm256_sll_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi64() { + let a = _mm256_set_epi64x(0xEEEEEEEE, -0xEEEEEEEE, 0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i(r, _mm256_set_epi64x(0xEEEEEEEE0, -0xEEEEEEEE0, 0xFFFFFFFF0, -0xFFFFFFFF0)); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + } + test_mm256_sll_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sra_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x8, -0x9, 0x9, -0xA, 0xA, -0xB, 0xB, -0xC, 0xC, -0xD, 0xD, -0xE, 0xE, -0xF, 0xF, + -0x10, + ), + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i( + r, + _mm256_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i( + r, + _mm256_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + ); + } + test_mm256_sra_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sra_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32(0xCCC, -0xCCD, 0xDDD, -0xDDE, 0xEEE, -0xEEF, 0xFFF, -0x1000), + ); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_setr_epi32(0, -1, 0, -1, 0, -1, 0, -1)); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_setr_epi32(0, -1, 0, -1, 0, -1, 0, -1)); + } + test_mm256_sra_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x8, 0xFF7, 0x9, 0xFF6, 0xA, 0xFF5, 0xB, 0xFF4, 0xC, 0xFF3, 0xD, 0xFF2, 0xE, 0xFF1, + 0xF, 0xFF0, + ), + ); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + } + test_mm256_srl_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32( + 0xCCC, 0xFFFF333, 0xDDD, 0xFFFF222, 0xEEE, 0xFFFF111, 0xFFF, 0xFFFF000, + ), + ); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + } + test_mm256_srl_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi64() { + let a = _mm256_set_epi64x(0xEEEEEEEE, -0xEEEEEEEE, 0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_set_epi64x(0xEEEEEEE, 0xFFFFFFFF1111111, 0xFFFFFFF, 0xFFFFFFFF0000000), + ); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + } + test_mm256_srl_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_sllv_epi32() { + let a = _mm_set_epi32(1, 2, 3, 4); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_sllv_epi32(a, b); + let e = _mm_set_epi32(16, 16, 12, 8); + assert_eq_m128i(r, e); + } + test_mm_sllv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sllv_epi32() { + let a = _mm256_set_epi32(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_sllv_epi32(a, b); + let e = _mm256_set_epi32(256, 256, 192, 128, 80, 48, 28, 16); + assert_eq_m256i(r, e); + } + test_mm256_sllv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_sllv_epi64() { + let a = _mm_set_epi64x(2, 3); + let b = _mm_set_epi64x(1, 2); + let r = _mm_sllv_epi64(a, b); + let e = _mm_set_epi64x(4, 12); + assert_eq_m128i(r, e); + } + test_mm_sllv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sllv_epi64() { + let a = _mm256_set_epi64x(1, 2, 3, 4); + let b = _mm256_set_epi64x(4, 3, 2, 1); + let r = _mm256_sllv_epi64(a, b); + let e = _mm256_set_epi64x(16, 16, 12, 8); + assert_eq_m256i(r, e); + } + test_mm256_sllv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srav_epi32() { + let a = _mm_set_epi32(16, -32, 64, -128); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_srav_epi32(a, b); + let e = _mm_set_epi32(1, -4, 16, -64); + assert_eq_m128i(r, e); + } + test_mm_srav_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srav_epi32() { + let a = _mm256_set_epi32(256, -512, 1024, -2048, 4096, -8192, 16384, -32768); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_srav_epi32(a, b); + let e = _mm256_set_epi32(1, -4, 16, -64, 256, -1024, 4096, -16384); + assert_eq_m256i(r, e); + } + test_mm256_srav_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srlv_epi32() { + let a = _mm_set_epi32(16, 32, 64, 128); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_srlv_epi32(a, b); + let e = _mm_set_epi32(1, 4, 16, 64); + assert_eq_m128i(r, e); + } + test_mm_srlv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srlv_epi32() { + let a = _mm256_set_epi32(256, 512, 1024, 2048, 4096, 8192, 16384, 32768); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_srlv_epi32(a, b); + let e = _mm256_set_epi32(1, 4, 16, 64, 256, 1024, 4096, 16384); + assert_eq_m256i(r, e); + } + test_mm256_srlv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srlv_epi64() { + let a = _mm_set_epi64x(4, 8); + let b = _mm_set_epi64x(2, 1); + let r = _mm_srlv_epi64(a, b); + let e = _mm_set_epi64x(1, 4); + assert_eq_m128i(r, e); + } + test_mm_srlv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srlv_epi64() { + let a = _mm256_set_epi64x(16, 32, 64, 128); + let b = _mm256_set_epi64x(4, 3, 2, 1); + let r = _mm256_srlv_epi64(a, b); + let e = _mm256_set_epi64x(1, 4, 16, 64); + assert_eq_m256i(r, e); + } + test_mm256_srlv_epi64(); +} + +#[target_feature(enable = "sse2")] +unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { + _mm_set_epi64x(b, a) +} + +#[track_caller] +#[target_feature(enable = "sse")] +unsafe fn assert_eq_m128(a: __m128, b: __m128) { + let r = _mm_cmpeq_ps(a, b); + if _mm_movemask_ps(r) != 0b1111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "sse2")] +unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { + if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "sse2")] +unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { + assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256(a: __m256, b: __m256) { + let cmp = _mm256_cmp_ps::<_CMP_EQ_OQ>(a, b); + if _mm256_movemask_ps(cmp) != 0b11111111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256d(a: __m256d, b: __m256d) { + let cmp = _mm256_cmp_pd::<_CMP_EQ_OQ>(a, b); + if _mm256_movemask_pd(cmp) != 0b1111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) +} + +/// Stores `T` in an unaligned address +struct Unaligned { + buf: Vec, + offset: bool, + _marker: std::marker::PhantomData, +} + +impl Unaligned { + fn new(value: T) -> Self { + // Allocate extra byte for unalignment headroom + let len = std::mem::size_of::(); + let mut buf = Vec::::with_capacity(len + 1); + // Force the address to be a non-multiple of 2, so it is as unaligned as it can get. + let offset = (buf.as_ptr() as usize % 2) == 0; + let value_ptr: *const T = &value; + unsafe { + buf.as_mut_ptr().add(offset.into()).copy_from_nonoverlapping(value_ptr.cast(), len); + } + Self { buf, offset, _marker: std::marker::PhantomData } + } + + fn as_ptr(&self) -> *const T { + unsafe { self.buf.as_ptr().add(self.offset.into()).cast() } + } + + fn as_mut_ptr(&mut self) -> *mut T { + unsafe { self.buf.as_mut_ptr().add(self.offset.into()).cast() } + } + + fn read(&self) -> T { + unsafe { self.as_ptr().read_unaligned() } + } +} diff --git a/src/tools/miri/tests/pass/issues/issue-miri-1909.rs b/src/tools/miri/tests/pass/issues/issue-miri-1909.rs index ce2114e760a32..8a2e67cdd09ec 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-1909.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-1909.rs @@ -9,7 +9,7 @@ use std::alloc::System; /// `ptr` must be valid for writes of `len` bytes unsafe fn volatile_write_zeroize_mem(ptr: *mut u8, len: usize) { for i in 0..len { - // ptr as usize + i can't overlow because `ptr` is valid for writes of `len` + // ptr as usize + i can't overflow because `ptr` is valid for writes of `len` let ptr_new: *mut u8 = ((ptr as usize) + i) as *mut u8; // SAFETY: `ptr` is valid for writes of `len` bytes, so `ptr_new` is valid for a // byte write diff --git a/src/tools/miri/tests/pass/path.rs b/src/tools/miri/tests/pass/path.rs new file mode 100644 index 0000000000000..fe99d38e073bf --- /dev/null +++ b/src/tools/miri/tests/pass/path.rs @@ -0,0 +1,60 @@ +//@compile-flags: -Zmiri-disable-isolation +use std::path::{absolute, Path, PathBuf}; + +#[path = "../utils/mod.rs"] +mod utils; + +#[track_caller] +fn assert_absolute_eq(in_: &str, out: &str) { + assert_eq!(absolute(in_).unwrap().as_os_str(), Path::new(out).as_os_str()); +} + +fn test_absolute() { + if cfg!(unix) { + assert_absolute_eq("/a/b/c", "/a/b/c"); + assert_absolute_eq("/a/b/c", "/a/b/c"); + assert_absolute_eq("/a//b/c", "/a/b/c"); + assert_absolute_eq("//a/b/c", "//a/b/c"); + assert_absolute_eq("///a/b/c", "/a/b/c"); + assert_absolute_eq("/a/b/c/", "/a/b/c/"); + assert_absolute_eq("/a/./b/../c/.././..", "/a/b/../c/../.."); + } else if cfg!(windows) { + // Test that all these are unchanged + assert_absolute_eq(r"C:\path\to\file", r"C:\path\to\file"); + assert_absolute_eq(r"C:\path\to\file\", r"C:\path\to\file\"); + assert_absolute_eq(r"\\server\share\to\file", r"\\server\share\to\file"); + assert_absolute_eq(r"\\server.\share.\to\file", r"\\server.\share.\to\file"); + assert_absolute_eq(r"\\.\PIPE\name", r"\\.\PIPE\name"); + assert_absolute_eq(r"\\.\C:\path\to\COM1", r"\\.\C:\path\to\COM1"); + assert_absolute_eq(r"\\?\C:\path\to\file", r"\\?\C:\path\to\file"); + assert_absolute_eq(r"\\?\UNC\server\share\to\file", r"\\?\UNC\server\share\to\file"); + assert_absolute_eq(r"\\?\PIPE\name", r"\\?\PIPE\name"); + // Verbatim paths are always unchanged, no matter what. + assert_absolute_eq(r"\\?\path.\to/file..", r"\\?\path.\to/file.."); + + assert_absolute_eq(r"C:\path..\to.\file.", r"C:\path..\to\file"); + assert_absolute_eq(r"COM1", r"\\.\COM1"); + } else { + panic!("unsupported OS"); + } +} + +fn buf_smoke(mut p: PathBuf) { + for _c in p.components() {} + + p.push("hello"); + for _c in p.components() {} + + if cfg!(windows) { + p.push(r"C:\mydir"); + } else { + p.push(r"/mydir"); + } + for _c in p.components() {} +} + +fn main() { + buf_smoke(PathBuf::new()); + buf_smoke(utils::tmp()); + test_absolute(); +} diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index cdb441b450b36..1fc713d48dcc4 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -#![feature(portable_simd, adt_const_params, inline_const, core_intrinsics)] +#![feature(portable_simd, adt_const_params, core_intrinsics)] #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; diff --git a/src/tools/miri/tests/pass/shims/env/home.rs b/src/tools/miri/tests/pass/shims/env/home.rs index 9eb9c3af569dd..c237f9ed9ffa5 100644 --- a/src/tools/miri/tests/pass/shims/env/home.rs +++ b/src/tools/miri/tests/pass/shims/env/home.rs @@ -1,9 +1,9 @@ -//@ignore-target-windows: home_dir is not supported on Windows //@compile-flags: -Zmiri-disable-isolation use std::env; fn main() { env::remove_var("HOME"); // make sure we enter the interesting codepath + env::remove_var("USERPROFILE"); // Windows also looks as this env var #[allow(deprecated)] env::home_dir().unwrap(); } diff --git a/src/tools/miri/tests/pass/shims/env/var-set.rs b/src/tools/miri/tests/pass/shims/env/var-set.rs new file mode 100644 index 0000000000000..2875b6c815a41 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/env/var-set.rs @@ -0,0 +1,7 @@ +// Test a value set on the host (MIRI_ENV_VAR_TEST) and one that is not. +//@compile-flags: -Zmiri-env-set=MIRI_ENV_VAR_TEST=test_value_1 -Zmiri-env-set=TEST_VAR_2=test_value_2 + +fn main() { + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("test_value_1".to_owned())); + assert_eq!(std::env::var("TEST_VAR_2"), Ok("test_value_2".to_owned())); +} diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index 23a3724ff7fd3..babaf00578a7a 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,4 +1,5 @@ use std::env; +use std::thread; fn main() { // Test that miri environment is isolated when communication is disabled. @@ -23,4 +24,11 @@ fn main() { env::remove_var("MIRI_TEST"); assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); println!("{:#?}", env::vars().collect::>()); + + // Do things concurrently, to make sure there's no data race. + let t = thread::spawn(|| { + env::set_var("MIRI_TEST", "42"); + }); + env::set_var("MIRI_TEST", "42"); + t.join().unwrap(); } diff --git a/src/tools/miri/tests/pass/shims/path.rs b/src/tools/miri/tests/pass/shims/path.rs deleted file mode 100644 index 9fc6e7faefbdd..0000000000000 --- a/src/tools/miri/tests/pass/shims/path.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@compile-flags: -Zmiri-disable-isolation -#![feature(absolute_path)] -use std::path::{absolute, Path}; - -#[track_caller] -fn test_absolute(in_: &str, out: &str) { - assert_eq!(absolute(in_).unwrap().as_os_str(), Path::new(out).as_os_str()); -} - -fn main() { - if cfg!(unix) { - test_absolute("/a/b/c", "/a/b/c"); - test_absolute("/a/b/c", "/a/b/c"); - test_absolute("/a//b/c", "/a/b/c"); - test_absolute("//a/b/c", "//a/b/c"); - test_absolute("///a/b/c", "/a/b/c"); - test_absolute("/a/b/c/", "/a/b/c/"); - test_absolute("/a/./b/../c/.././..", "/a/b/../c/../.."); - } else if cfg!(windows) { - // Test that all these are unchanged - test_absolute(r"C:\path\to\file", r"C:\path\to\file"); - test_absolute(r"C:\path\to\file\", r"C:\path\to\file\"); - test_absolute(r"\\server\share\to\file", r"\\server\share\to\file"); - test_absolute(r"\\server.\share.\to\file", r"\\server.\share.\to\file"); - test_absolute(r"\\.\PIPE\name", r"\\.\PIPE\name"); - test_absolute(r"\\.\C:\path\to\COM1", r"\\.\C:\path\to\COM1"); - test_absolute(r"\\?\C:\path\to\file", r"\\?\C:\path\to\file"); - test_absolute(r"\\?\UNC\server\share\to\file", r"\\?\UNC\server\share\to\file"); - test_absolute(r"\\?\PIPE\name", r"\\?\PIPE\name"); - // Verbatim paths are always unchanged, no matter what. - test_absolute(r"\\?\path.\to/file..", r"\\?\path.\to/file.."); - - test_absolute(r"C:\path..\to.\file.", r"C:\path..\to\file"); - test_absolute(r"COM1", r"\\.\COM1"); - } else { - panic!("unsupported OS"); - } -} diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs index c4b15c8758bef..259fc72d3929e 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs @@ -1,6 +1,6 @@ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: // this fails when Stacked Borrows is strictly applied even to `!Unpin` types. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::{Coroutine, CoroutineState}, @@ -8,6 +8,7 @@ use std::{ }; fn firstn() -> impl Coroutine { + #[coroutine] static move || { let mut num = 0; let num = &mut num; diff --git a/src/tools/miri/tests/pass/track-caller-attribute.rs b/src/tools/miri/tests/pass/track-caller-attribute.rs index d88bcc98858f5..c3803af3cc8ec 100644 --- a/src/tools/miri/tests/pass/track-caller-attribute.rs +++ b/src/tools/miri/tests/pass/track-caller-attribute.rs @@ -232,7 +232,7 @@ fn test_coroutine() { } #[rustfmt::skip] - let coroutine = #[track_caller] |arg: String| { + let coroutine = #[track_caller] #[coroutine] |arg: String| { yield ("first", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller()); }; @@ -255,7 +255,7 @@ fn test_coroutine() { assert_eq!(mono_loc.column(), 42); #[rustfmt::skip] - let non_tracked_coroutine = || { yield Location::caller(); }; + let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); }; let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) { CoroutineState::Yielded(val) => val, @@ -263,7 +263,7 @@ fn test_coroutine() { }; assert_eq!(non_tracked_loc.file(), file!()); assert_eq!(non_tracked_loc.line(), non_tracked_line); - assert_eq!(non_tracked_loc.column(), 44); + assert_eq!(non_tracked_loc.column(), 57); } fn main() { diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index ace0da0125361..efeefbe29fbce 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -1,6 +1,7 @@ use std::ffi::OsString; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; +use std::sync::OnceLock; use std::{env, process::Command}; use colored::*; @@ -67,8 +68,8 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> let mut config = Config { target: Some(target.to_owned()), - stderr_filters: STDERR.clone(), - stdout_filters: STDOUT.clone(), + stderr_filters: stderr_filters().into(), + stdout_filters: stdout_filters().into(), mode, program, out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("ui"), @@ -174,15 +175,18 @@ fn run_tests( } macro_rules! regexes { - ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! { - static ref $name: Vec<(Match, &'static [u8])> = vec![ - $((Regex::new($regex).unwrap().into(), $replacement.as_bytes()),)* - ]; - }}; + ($name:ident: $($regex:expr => $replacement:expr,)*) => { + fn $name() -> &'static [(Match, &'static [u8])] { + static S: OnceLock> = OnceLock::new(); + S.get_or_init(|| vec![ + $((Regex::new($regex).unwrap().into(), $replacement.as_bytes()),)* + ]) + } + }; } regexes! { - STDOUT: + stdout_filters: // Windows file paths r"\\" => "/", // erase borrow tags @@ -191,7 +195,7 @@ regexes! { } regexes! { - STDERR: + stderr_filters: // erase line and column info r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", // erase alloc ids diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3ea35c7940c21..cf4ae4b16cd56 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -5,5 +5,7 @@ edition = "2021" [dependencies] object = "0.34.0" +similar = "2.5.0" wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace +gimli = "0.28.1" diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs new file mode 100644 index 0000000000000..332126939c084 --- /dev/null +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -0,0 +1,103 @@ +use regex::Regex; +use similar::TextDiff; +use std::path::Path; + +#[cfg(test)] +mod tests; + +pub fn diff() -> Diff { + Diff::new() +} + +#[derive(Debug)] +pub struct Diff { + expected: Option, + expected_name: Option, + actual: Option, + actual_name: Option, + normalizers: Vec<(String, String)>, +} + +impl Diff { + /// Construct a bare `diff` invocation. + pub fn new() -> Self { + Self { + expected: None, + expected_name: None, + actual: None, + actual_name: None, + normalizers: Vec::new(), + } + } + + /// Specify the expected output for the diff from a file. + pub fn expected_file>(&mut self, path: P) -> &mut Self { + let path = path.as_ref(); + let content = std::fs::read_to_string(path).expect("failed to read file"); + let name = path.to_string_lossy().to_string(); + + self.expected = Some(content); + self.expected_name = Some(name); + self + } + + /// Specify the expected output for the diff from a given text string. + pub fn expected_text>(&mut self, name: &str, text: T) -> &mut Self { + self.expected = Some(String::from_utf8_lossy(text.as_ref()).to_string()); + self.expected_name = Some(name.to_string()); + self + } + + /// Specify the actual output for the diff from a file. + pub fn actual_file>(&mut self, path: P) -> &mut Self { + let path = path.as_ref(); + let content = std::fs::read_to_string(path).expect("failed to read file"); + let name = path.to_string_lossy().to_string(); + + self.actual = Some(content); + self.actual_name = Some(name); + self + } + + /// Specify the actual output for the diff from a given text string. + pub fn actual_text>(&mut self, name: &str, text: T) -> &mut Self { + self.actual = Some(String::from_utf8_lossy(text.as_ref()).to_string()); + self.actual_name = Some(name.to_string()); + self + } + + /// Specify a regex that should replace text in the "actual" text that will be compared. + pub fn normalize, I: Into>( + &mut self, + regex: R, + replacement: I, + ) -> &mut Self { + self.normalizers.push((regex.into(), replacement.into())); + self + } + + /// Executes the diff process, prints any differences to the standard error. + #[track_caller] + pub fn run(&self) { + let expected = self.expected.as_ref().expect("expected text not set"); + let mut actual = self.actual.as_ref().expect("actual text not set").to_string(); + let expected_name = self.expected_name.as_ref().unwrap(); + let actual_name = self.actual_name.as_ref().unwrap(); + for (regex, replacement) in &self.normalizers { + let re = Regex::new(regex).expect("bad regex in custom normalization rule"); + actual = re.replace_all(&actual, replacement).into_owned(); + } + + let output = TextDiff::from_lines(expected, &actual) + .unified_diff() + .header(expected_name, actual_name) + .to_string(); + + if !output.is_empty() { + panic!( + "test failed: `{}` is different from `{}`\n\n{}", + expected_name, actual_name, output + ) + } + } +} diff --git a/src/tools/run-make-support/src/diff/tests.rs b/src/tools/run-make-support/src/diff/tests.rs new file mode 100644 index 0000000000000..286548bef618f --- /dev/null +++ b/src/tools/run-make-support/src/diff/tests.rs @@ -0,0 +1,61 @@ +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn test_diff() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbar\nbaz\n"; + diff().expected_text("EXPECTED_TEXT", expected).actual_text("ACTUAL_TEXT", actual).run(); + } + + #[test] + fn test_should_panic() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbaz\nbar\n"; + + let output = std::panic::catch_unwind(|| { + diff() + .expected_text("EXPECTED_TEXT", expected) + .actual_text("ACTUAL_TEXT", actual) + .run(); + }) + .unwrap_err(); + + let expected_output = "\ +test failed: `EXPECTED_TEXT` is different from `ACTUAL_TEXT` + +--- EXPECTED_TEXT ++++ ACTUAL_TEXT +@@ -1,3 +1,3 @@ + foo ++baz + bar +-baz +"; + + assert_eq!(output.downcast_ref::().unwrap(), expected_output); + } + + #[test] + fn test_normalize() { + let expected = " +running 2 tests +.. + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +"; + let actual = " +running 2 tests +.. + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s +"; + + diff() + .expected_text("EXPECTED_TEXT", expected) + .actual_text("ACTUAL_TEXT", actual) + .normalize(r#"finished in \d+\.\d+s"#, "finished in $$TIME") + .run(); + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e723e824ed6c8..a874c1313b510 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -5,6 +5,7 @@ pub mod cc; pub mod clang; +pub mod diff; pub mod llvm_readobj; pub mod run; pub mod rustc; @@ -14,12 +15,14 @@ use std::env; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; +pub use gimli; pub use object; pub use regex; pub use wasmparser; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; +pub use diff::{diff, Diff}; pub use llvm_readobj::{llvm_readobj, LlvmReadobj}; pub use run::{run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 9bf41c6e2e9a5..ddaae3236c2b5 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -148,6 +148,13 @@ impl Rustc { self } + /// Specify the print request. + pub fn print(&mut self, request: &str) -> &mut Self { + self.cmd.arg("--print"); + self.cmd.arg(request); + self + } + /// Add an extra argument to the linker invocation, via `-Clink-arg`. pub fn link_arg(&mut self, link_arg: &str) -> &mut Self { self.cmd.arg(format!("-Clink-arg={link_arg}")); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index d50088e6cf1d9..c92d4e78ffa71 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -3869,7 +3869,7 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; @@ -3901,7 +3901,7 @@ use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { println!("2"); yield; println!("4"); @@ -4007,7 +4007,7 @@ use std::pin::Pin; fn main() { let ret = "foo"; - let mut coroutine = move || { + let mut coroutine = #[coroutine] move || { yield 1; return ret }; diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index f6f51fbd8eaf9..e196d1817f34a 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -3325,11 +3325,11 @@ impl Rewrite for ast::ForeignItem { .map(|(s, _, _)| format!("{};", s)) } } - ast::ForeignItemKind::Static(ref ty, mutability, _) => { + ast::ForeignItemKind::Static(ref static_foreign_item) => { // FIXME(#21): we're dropping potential comments in between the // function kw here. let vis = format_visibility(context, &self.vis); - let mut_str = format_mutability(mutability); + let mut_str = format_mutability(static_foreign_item.mutability); let prefix = format!( "{}static {}{}:", vis, @@ -3340,7 +3340,7 @@ impl Rewrite for ast::ForeignItem { rewrite_assign_rhs( context, prefix, - &**ty, + &static_foreign_item.ty, &RhsAssignKind::Ty, shape.sub_width(1)?, ) diff --git a/src/tools/rustfmt/tests/source/attrib.rs b/src/tools/rustfmt/tests/source/attrib.rs index d45fba5522436..fc13cd02b03ef 100644 --- a/src/tools/rustfmt/tests/source/attrib.rs +++ b/src/tools/rustfmt/tests/source/attrib.rs @@ -214,8 +214,8 @@ type Os = NoSource; // #3313 fn stmt_expr_attributes() { let foo ; - #[must_use] - foo = false ; + (#[must_use] + foo) = false ; } // #3509 diff --git a/src/tools/rustfmt/tests/source/immovable_coroutines.rs b/src/tools/rustfmt/tests/source/immovable_coroutines.rs index 3b94af0c96ce4..539049577a00e 100644 --- a/src/tools/rustfmt/tests/source/immovable_coroutines.rs +++ b/src/tools/rustfmt/tests/source/immovable_coroutines.rs @@ -1,7 +1,8 @@ #![feature(coroutines)] unsafe fn foo() { - let mut ga = static || { + let mut ga = #[coroutine] + static || { yield 1; }; } diff --git a/src/tools/rustfmt/tests/target/attrib.rs b/src/tools/rustfmt/tests/target/attrib.rs index 7e61f68d76a14..7b3309676de2f 100644 --- a/src/tools/rustfmt/tests/target/attrib.rs +++ b/src/tools/rustfmt/tests/target/attrib.rs @@ -248,8 +248,8 @@ type Os = NoSource; // #3313 fn stmt_expr_attributes() { let foo; - #[must_use] - foo = false; + (#[must_use] + foo) = false; } // #3509 diff --git a/src/tools/rustfmt/tests/target/immovable_coroutines.rs b/src/tools/rustfmt/tests/target/immovable_coroutines.rs index f52cfa00f9783..539049577a00e 100644 --- a/src/tools/rustfmt/tests/target/immovable_coroutines.rs +++ b/src/tools/rustfmt/tests/target/immovable_coroutines.rs @@ -1,7 +1,8 @@ #![feature(coroutines)] unsafe fn foo() { - let mut ga = static || { + let mut ga = #[coroutine] + static || { yield 1; }; } diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml index f4f4d548bb79e..7c048d53a505f 100644 --- a/src/tools/suggest-tests/Cargo.toml +++ b/src/tools/suggest-tests/Cargo.toml @@ -6,4 +6,3 @@ edition = "2021" [dependencies] glob = "0.3.0" build_helper = { version = "0.1.0", path = "../build_helper" } -once_cell = "1.17.1" diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs index 1c1d9d0333ddb..8932403ac9fd5 100644 --- a/src/tools/suggest-tests/src/lib.rs +++ b/src/tools/suggest-tests/src/lib.rs @@ -5,7 +5,7 @@ use std::{ use dynamic_suggestions::DYNAMIC_SUGGESTIONS; use glob::Pattern; -use static_suggestions::STATIC_SUGGESTIONS; +use static_suggestions::static_suggestions; mod dynamic_suggestions; mod static_suggestions; @@ -33,7 +33,7 @@ pub fn get_suggestions>(modified_files: &[T]) -> Vec { let mut suggestions = Vec::new(); // static suggestions - for (globs, sugs) in STATIC_SUGGESTIONS.iter() { + for (globs, sugs) in static_suggestions().iter() { let globs = globs .iter() .map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!")) diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs index fbd265ea42a2e..a34a4b16ec1b6 100644 --- a/src/tools/suggest-tests/src/static_suggestions.rs +++ b/src/tools/suggest-tests/src/static_suggestions.rs @@ -1,10 +1,14 @@ use crate::{sug, Suggestion}; +use std::sync::OnceLock; // FIXME: perhaps this could use `std::lazy` when it is stablizied macro_rules! static_suggestions { ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => { - pub(crate) const STATIC_SUGGESTIONS: ::once_cell::unsync::Lazy, Vec)>> - = ::once_cell::unsync::Lazy::new(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]); + pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec)] + { + static S: OnceLock, Vec)>> = OnceLock::new(); + S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]) + } } } diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 96866e7424889..63963b0bd1ced 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -8,7 +8,6 @@ autobins = false cargo_metadata = "0.15" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } -lazy_static = "1" walkdir = "2" ignore = "0.4.18" semver = "1.0" diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f0ed0ae806fd8..69c6dda4b19cf 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -189,7 +189,6 @@ run-make/no-builtins-attribute/Makefile run-make/no-builtins-lto/Makefile run-make/no-cdylib-as-rdylib/Makefile run-make/no-duplicate-libs/Makefile -run-make/no-input-file/Makefile run-make/no-intermediate-extras/Makefile run-make/obey-crate-type-flag/Makefile run-make/optimization-remarks-dir-pgo/Makefile @@ -220,8 +219,6 @@ run-make/prefer-rlib/Makefile run-make/pretty-print-to-file/Makefile run-make/pretty-print-with-dep-file/Makefile run-make/print-calling-conventions/Makefile -run-make/print-cfg/Makefile -run-make/print-native-static-libs/Makefile run-make/print-target-list/Makefile run-make/profile/Makefile run-make/prune-link-args/Makefile @@ -238,7 +235,6 @@ run-make/relocation-model/Makefile run-make/relro-levels/Makefile run-make/remap-path-prefix-dwarf/Makefile run-make/remap-path-prefix/Makefile -run-make/repr128-dwarf/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile run-make/resolve-rename/Makefile @@ -317,7 +313,6 @@ run-make/unstable-flag-required/Makefile run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile run-make/used/Makefile -run-make/valid-print-requests/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f380513f4ef2d..1d24c59b356f2 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -491,6 +491,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d673ce7a736d9..3e84bf3c34be5 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -17,8 +17,6 @@ use std::fs; use std::num::NonZeroU32; use std::path::{Path, PathBuf}; -use regex::Regex; - #[cfg(test)] mod tests; @@ -251,16 +249,10 @@ fn format_features<'a>( } fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - lazy_static::lazy_static! { - static ref ISSUE: Regex = Regex::new(r#"issue\s*=\s*"([^"]*)""#).unwrap(); - static ref FEATURE: Regex = Regex::new(r#"feature\s*=\s*"([^"]*)""#).unwrap(); - static ref SINCE: Regex = Regex::new(r#"since\s*=\s*"([^"]*)""#).unwrap(); - } - let r = match attr { - "issue" => &*ISSUE, - "feature" => &*FEATURE, - "since" => &*SINCE, + "issue" => static_regex!(r#"issue\s*=\s*"([^"]*)""#), + "feature" => static_regex!(r#"feature\s*=\s*"([^"]*)""#), + "since" => static_regex!(r#"since\s*=\s*"([^"]*)""#), _ => unimplemented!("{attr} not handled"), }; @@ -528,11 +520,8 @@ fn map_lib_features( }}; } - lazy_static::lazy_static! { - static ref COMMENT_LINE: Regex = Regex::new(r"^\s*//").unwrap(); - } // exclude commented out lines - if COMMENT_LINE.is_match(line) { + if static_regex!(r"^\s*//").is_match(line) { continue; } diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs index 9803b6eab2db5..a85367984deef 100644 --- a/src/tools/tidy/src/fluent_alphabetical.rs +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -6,8 +6,8 @@ use std::{fs::OpenOptions, io::Write, path::Path}; use regex::Regex; -lazy_static::lazy_static! { - static ref MESSAGE: Regex = Regex::new(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#).unwrap(); +fn message() -> &'static Regex { + static_regex!(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#) } fn filter_fluent(path: &Path) -> bool { @@ -20,7 +20,7 @@ fn check_alphabetic( bad: &mut bool, all_defined_msgs: &mut HashMap, ) { - let mut matches = MESSAGE.captures_iter(fluent).peekable(); + let mut matches = message().captures_iter(fluent).peekable(); while let Some(m) = matches.next() { let name = m.get(1).unwrap(); if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) { @@ -60,7 +60,7 @@ fn sort_messages( let mut chunks = vec![]; let mut cur = String::new(); for line in fluent.lines() { - if let Some(name) = MESSAGE.find(line) { + if let Some(name) = message().find(line) { if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) { tidy_error!( bad, diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs index b73e79cb38d94..8b6c6c18813d4 100644 --- a/src/tools/tidy/src/fluent_used.rs +++ b/src/tools/tidy/src/fluent_used.rs @@ -1,14 +1,9 @@ //! Checks that all Fluent messages appear at least twice use crate::walk::{filter_dirs, walk}; -use regex::Regex; use std::collections::HashMap; use std::path::Path; -lazy_static::lazy_static! { - static ref WORD: Regex = Regex::new(r"\w+").unwrap(); -} - fn filter_used_messages( contents: &str, msgs_not_appeared_yet: &mut HashMap, @@ -17,7 +12,7 @@ fn filter_used_messages( // we don't just check messages never appear in Rust files, // because messages can be used as parts of other fluent messages in Fluent files, // so we do checking messages appear only once in all Rust and Fluent files. - let mut matches = WORD.find_iter(contents); + let mut matches = static_regex!(r"\w+").find_iter(contents); while let Some(name) = matches.next() { if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) { // if one msg appears for the first time, diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index dff15265fae78..4f02a61f7bc7b 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -439,7 +439,6 @@ ui/closures/issue-11873.rs ui/closures/issue-1460.rs ui/closures/issue-22864-1.rs ui/closures/issue-22864-2.rs -ui/closures/issue-23012-supertrait-signature-inference.rs ui/closures/issue-25439.rs ui/closures/issue-41366.rs ui/closures/issue-42463.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 23f303276aa2d..c15081a56d1a8 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -5,6 +5,13 @@ use termcolor::WriteColor; +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} + /// A helper macro to `unwrap` a result except also print out details like: /// /// * The expression that failed diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index a1445ce5896b0..9cabab582d0d8 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -18,7 +18,7 @@ // ignore-tidy-dbg use crate::walk::{filter_dirs, walk}; -use regex::{Regex, RegexSet}; +use regex::RegexSet; use rustc_hash::FxHashMap; use std::{ffi::OsStr, path::Path}; @@ -178,20 +178,14 @@ fn should_ignore(line: &str) -> bool { // Matches test annotations like `//~ ERROR text`. // This mirrors the regex in src/tools/compiletest/src/runtest.rs, please // update both if either are changed. - lazy_static::lazy_static! { - static ref ANNOTATION_RE: Regex = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap(); - } + static_regex!("\\s*//(\\[.*\\])?~.*").is_match(line) + || ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a)) + // For `ui_test`-style UI test directives, also ignore // - `//@[rev] compile-flags` // - `//@[rev] normalize-stderr-test` - lazy_static::lazy_static! { - static ref UI_TEST_LONG_DIRECTIVES_RE: Regex = - Regex::new("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*") - .unwrap(); - } - ANNOTATION_RE.is_match(line) - || ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a)) - || UI_TEST_LONG_DIRECTIVES_RE.is_match(line) + || static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*") + .is_match(line) } /// Returns `true` if `line` is allowed to be longer than the normal limit. @@ -226,6 +220,7 @@ fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> if contents.contains(&format!("// ignore-tidy-{check}")) || contents.contains(&format!("# ignore-tidy-{check}")) || contents.contains(&format!("/* ignore-tidy-{check} */")) + || contents.contains(&format!("")) { Directive::Ignore(false) } else { @@ -352,7 +347,8 @@ pub fn check(path: &Path, bad: &mut bool) { let can_contain = contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-") - || contents.contains("/* ignore-tidy-"); + || contents.contains("/* ignore-tidy-") + || contents.contains(" MC/DC Decision Region (LL:8) to (LL:46) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + |---> MC/DC Decision Region (LL:16) to (LL:22) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:16) + | Condition C2 --> (LL:21) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, F = F } + | 2 { T, - = T } + | 3 { F, T = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: covered: (1,3) + | MC/DC Coverage for Decision: 100.00% + | + ------------------ + LL| 2| say("yes"); + LL| 2| } else { + LL| 2| say("no"); + LL| 2| } + LL| 4|} + LL| | + LL| 4|fn doubly_nested_if_in_condition(a: bool, b: bool, c: bool, d: bool) { + LL| 4| if a && if b || if c && d { true } else { false } { false } else { true } { + ^3 ^2 ^1 ^1 ^1 ^2 ^1 + ------------------ + |---> MC/DC Decision Region (LL:8) to (LL:78) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + |---> MC/DC Decision Region (LL:16) to (LL:54) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:16) + | Condition C2 --> (LL:21) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, F = F } + | 2 { T, - = T } + | 3 { F, T = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: covered: (1,3) + | MC/DC Coverage for Decision: 100.00% + | + |---> MC/DC Decision Region (LL:24) to (LL:30) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:24) + | Condition C2 --> (LL:29) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, T = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: not covered + | MC/DC Coverage for Decision: 50.00% + | + ------------------ + LL| 1| say("yes"); + LL| 3| } else { + LL| 3| say("no"); + LL| 3| } + LL| 4|} + LL| | + LL| 3|fn nested_single_condition_decision(a: bool, b: bool) { + LL| 3| // Decision with only 1 decision should not be instrumented by MCDC because + LL| 3| // branch-coverage is equivalent to MCDC coverage in this case, and we don't + LL| 3| // want to waste bitmap space for this. + LL| 3| if a && if b { false } else { true } { + ^2 ^1 ^1 + ------------------ + |---> MC/DC Decision Region (LL:8) to (LL:41) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + ------------------ + LL| 1| say("yes"); + LL| 2| } else { + LL| 2| say("no"); + LL| 2| } + LL| 3|} + LL| | + LL| 7|fn nested_in_then_block_in_condition(a: bool, b: bool, c: bool, d: bool, e: bool) { + LL| 7| if a && if b || c { if d && e { true } else { false } } else { false } { + ^6 ^5 ^5 ^2 ^1 ^4 ^1 + ------------------ + |---> MC/DC Decision Region (LL:8) to (LL:75) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + |---> MC/DC Decision Region (LL:16) to (LL:22) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:16) + | Condition C2 --> (LL:21) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, F = F } + | 2 { T, - = T } + | 3 { F, T = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: covered: (1,3) + | MC/DC Coverage for Decision: 100.00% + | + |---> MC/DC Decision Region (LL:28) to (LL:34) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:28) + | Condition C2 --> (LL:33) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + ------------------ + LL| 1| say("yes"); + LL| 6| } else { + LL| 6| say("no"); + LL| 6| } + LL| 7|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | nested_if_in_condition(true, false, false); + LL| | nested_if_in_condition(true, true, true); + LL| | nested_if_in_condition(true, false, true); + LL| | nested_if_in_condition(false, true, true); + LL| | + LL| | doubly_nested_if_in_condition(true, false, false, true); + LL| | doubly_nested_if_in_condition(true, true, true, true); + LL| | doubly_nested_if_in_condition(true, false, true, true); + LL| | doubly_nested_if_in_condition(false, true, true, true); + LL| | + LL| | nested_single_condition_decision(true, true); + LL| | nested_single_condition_decision(true, false); + LL| | nested_single_condition_decision(false, false); + LL| | + LL| | nested_in_then_block_in_condition(false, false, false, false, false); + LL| | nested_in_then_block_in_condition(true, false, false, false, false); + LL| | nested_in_then_block_in_condition(true, true, false, false, false); + LL| | nested_in_then_block_in_condition(true, false, true, false, false); + LL| | nested_in_then_block_in_condition(true, false, true, true, false); + LL| | nested_in_then_block_in_condition(true, false, true, false, true); + LL| | nested_in_then_block_in_condition(true, false, true, true, true); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn say(message: &str) { + LL| | core::hint::black_box(message); + LL| |} + diff --git a/tests/coverage/mcdc_nested_if.rs b/tests/coverage/mcdc_nested_if.rs new file mode 100644 index 0000000000000..3d869771f75b5 --- /dev/null +++ b/tests/coverage/mcdc_nested_if.rs @@ -0,0 +1,70 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ compile-flags: -Zcoverage-options=mcdc +//@ llvm-cov-flags: --show-mcdc + +fn nested_if_in_condition(a: bool, b: bool, c: bool) { + if a && if b || c { true } else { false } { + say("yes"); + } else { + say("no"); + } +} + +fn doubly_nested_if_in_condition(a: bool, b: bool, c: bool, d: bool) { + if a && if b || if c && d { true } else { false } { false } else { true } { + say("yes"); + } else { + say("no"); + } +} + +fn nested_single_condition_decision(a: bool, b: bool) { + // Decision with only 1 decision should not be instrumented by MCDC because + // branch-coverage is equivalent to MCDC coverage in this case, and we don't + // want to waste bitmap space for this. + if a && if b { false } else { true } { + say("yes"); + } else { + say("no"); + } +} + +fn nested_in_then_block_in_condition(a: bool, b: bool, c: bool, d: bool, e: bool) { + if a && if b || c { if d && e { true } else { false } } else { false } { + say("yes"); + } else { + say("no"); + } +} + +#[coverage(off)] +fn main() { + nested_if_in_condition(true, false, false); + nested_if_in_condition(true, true, true); + nested_if_in_condition(true, false, true); + nested_if_in_condition(false, true, true); + + doubly_nested_if_in_condition(true, false, false, true); + doubly_nested_if_in_condition(true, true, true, true); + doubly_nested_if_in_condition(true, false, true, true); + doubly_nested_if_in_condition(false, true, true, true); + + nested_single_condition_decision(true, true); + nested_single_condition_decision(true, false); + nested_single_condition_decision(false, false); + + nested_in_then_block_in_condition(false, false, false, false, false); + nested_in_then_block_in_condition(true, false, false, false, false); + nested_in_then_block_in_condition(true, true, false, false, false); + nested_in_then_block_in_condition(true, false, true, false, false); + nested_in_then_block_in_condition(true, false, true, true, false); + nested_in_then_block_in_condition(true, false, true, false, true); + nested_in_then_block_in_condition(true, false, true, true, true); +} + +#[coverage(off)] +fn say(message: &str) { + core::hint::black_box(message); +} diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index 9cc67dfe88ac4..0347aaaa36765 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -41,21 +41,21 @@ Number of file 0 mappings: 16 - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 1c, 01, 10, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 8, 28) to (start + 1, 16) +- Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 16) +- Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) diff --git a/tests/coverage/yield.coverage b/tests/coverage/yield.coverage index d7e455f211e45..e2fc9196d2444 100644 --- a/tests/coverage/yield.coverage +++ b/tests/coverage/yield.coverage @@ -1,11 +1,11 @@ - LL| |#![feature(coroutines, coroutine_trait)] + LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] LL| |#![allow(unused_assignments)] LL| | LL| |use std::ops::{Coroutine, CoroutineState}; LL| |use std::pin::Pin; LL| | LL| 1|fn main() { - LL| 1| let mut coroutine = || { + LL| 1| let mut coroutine = #[coroutine] || { LL| 1| yield 1; LL| 1| return "foo"; LL| 1| }; @@ -19,7 +19,7 @@ LL| 0| _ => panic!("unexpected value from resume"), LL| | } LL| | - LL| 1| let mut coroutine = || { + LL| 1| let mut coroutine = #[coroutine] || { LL| 1| yield 1; LL| 1| yield 2; LL| 0| yield 3; diff --git a/tests/coverage/yield.rs b/tests/coverage/yield.rs index b7e2ba31b59c1..64ea27066047e 100644 --- a/tests/coverage/yield.rs +++ b/tests/coverage/yield.rs @@ -1,11 +1,11 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(unused_assignments)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo"; }; @@ -19,7 +19,7 @@ fn main() { _ => panic!("unexpected value from resume"), } - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; yield 2; yield 3; diff --git a/tests/crashes/109812.rs b/tests/crashes/109812.rs new file mode 100644 index 0000000000000..c29b874652153 --- /dev/null +++ b/tests/crashes/109812.rs @@ -0,0 +1,22 @@ +//@ known-bug: #109812 + +#![warn(rust_2021_incompatible_closure_captures)] + +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn move_into_fnmut() { + let x = X(Y); + + consume_fnmut(|| { + let Either::Two(ref mut _t) = x; + + let X(mut _t) = x; + }); +} diff --git a/tests/crashes/122552.rs b/tests/crashes/122552.rs deleted file mode 100644 index 29566941e22b2..0000000000000 --- a/tests/crashes/122552.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #122552 -//@ edition:2021 - -trait X { - fn line_stream<'a, Repr>() -> Self::LineStreamFut<{ async {} }, Repr>; -} - -struct Y; - -pub fn main() {} diff --git a/tests/crashes/123461.rs b/tests/crashes/123461.rs deleted file mode 100644 index 6dbfb5c809288..0000000000000 --- a/tests/crashes/123461.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #123461 - -fn main() { - let _: [_; unsafe { std::mem::transmute(|o_b: Option<_>| {}) }]; -} diff --git a/tests/crashes/123710.rs b/tests/crashes/123710.rs deleted file mode 100644 index f171fa7cebb4a..0000000000000 --- a/tests/crashes/123710.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #123710 - -#[repr(packed)] -#[repr(u32)] -enum E { - A, - B, - C, -} - -fn main() { - union InvalidTag { - int: u32, - e: E, - } - let _invalid_tag = InvalidTag { int: 4 }; -} diff --git a/tests/crashes/123863.rs b/tests/crashes/123863.rs deleted file mode 100644 index e0f3ac9dcd729..0000000000000 --- a/tests/crashes/123863.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #123863 -const fn concat_strs() -> &'static str { - struct Inner; - Inner::concat_strs::<"a">::A -} -pub fn main() {} diff --git a/tests/crashes/124262.rs b/tests/crashes/124262.rs new file mode 100644 index 0000000000000..b9dac5eca2276 --- /dev/null +++ b/tests/crashes/124262.rs @@ -0,0 +1,5 @@ +//@ known-bug: #124262 +//@ edition:2021 + +struct Foo(<&[fn()] as ::core::ops::Deref>::Target); +const _: *const Foo = 0 as _; diff --git a/tests/crashes/124340.rs b/tests/crashes/124340.rs new file mode 100644 index 0000000000000..cdf24fa039590 --- /dev/null +++ b/tests/crashes/124340.rs @@ -0,0 +1,17 @@ +//@ known-bug: #124340 +#![feature(anonymous_lifetime_in_impl_trait)] + +trait Producer { + type Output; + fn produce(self) -> Self::Output; +} + +trait SomeTrait<'a> {} + +fn force_same_lifetime<'a>(_x: &'a i32, _y: impl SomeTrait<'a>) { + unimplemented!() +} + +fn foo<'a>(s: &'a i32, producer: impl Producer>) { + force_same_lifetime(s, producer.produce()); +} diff --git a/tests/crashes/124342.rs b/tests/crashes/124342.rs new file mode 100644 index 0000000000000..ae51b3db96f5d --- /dev/null +++ b/tests/crashes/124342.rs @@ -0,0 +1,6 @@ +//@ known-bug: #124342 +trait Trait2 : Trait { + reuse <() as Trait>::async { + (async || {}).await; + }; +} diff --git a/tests/crashes/124347.rs b/tests/crashes/124347.rs new file mode 100644 index 0000000000000..d2bc555fe1c7b --- /dev/null +++ b/tests/crashes/124347.rs @@ -0,0 +1,4 @@ +//@ known-bug: #124347 +trait Trait: ToReuse { + reuse Trait::lolno { &self.0 }; +} diff --git a/tests/crashes/124348.rs b/tests/crashes/124348.rs new file mode 100644 index 0000000000000..554f383026cbd --- /dev/null +++ b/tests/crashes/124348.rs @@ -0,0 +1,7 @@ +//@ known-bug: #124348 +enum Eek { + TheConst, + UnusedByTheConst(Sum), +} + +const EEK_ZERO: &[Eek] = &[]; diff --git a/tests/crashes/124350.rs b/tests/crashes/124350.rs new file mode 100644 index 0000000000000..d6038f280cf81 --- /dev/null +++ b/tests/crashes/124350.rs @@ -0,0 +1,17 @@ +//@ known-bug: #124350 + +struct Node {} + +impl Node +where + SmallVec<{ D * 2 }>:, +{ + fn new() -> Self { + let mut node = Node::new(); + (&a, 0)(); + + node + } +} + +struct SmallVec {} diff --git a/tests/crashes/124352.rs b/tests/crashes/124352.rs new file mode 100644 index 0000000000000..e9eb4419e6a4f --- /dev/null +++ b/tests/crashes/124352.rs @@ -0,0 +1,4 @@ +//@ known-bug: #124352 +#![rustc_never_type_options(: Unsize = "hi")] + +fn main() {} diff --git a/tests/crashes/124375.rs b/tests/crashes/124375.rs new file mode 100644 index 0000000000000..7165655178d7d --- /dev/null +++ b/tests/crashes/124375.rs @@ -0,0 +1,11 @@ +//@ known-bug: #124375 +//@ compile-flags: -Zmir-opt-level=0 +//@ only-x86_64 +#![crate_type = "lib"] +#![feature(naked_functions)] +use std::arch::asm; + +#[naked] +pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { + asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); +} diff --git a/tests/crashes/92470.rs b/tests/crashes/92470.rs new file mode 100644 index 0000000000000..a3c518f5ec62f --- /dev/null +++ b/tests/crashes/92470.rs @@ -0,0 +1,31 @@ +//@ known-bug: #92470 +fn main() { + encode(&mut EncoderImpl); +} + +pub trait Encoder { + type W; + + fn writer(&self) -> Self::W; +} + +fn encode(mut encoder: E) { + encoder.writer(); + encode(&mut encoder); +} + +struct EncoderImpl; + +impl Encoder for EncoderImpl { + type W = (); + + fn writer(&self) {} +} + +impl<'a, T: Encoder> Encoder for &'a mut T { + type W = T::W; + + fn writer(&self) -> Self::W { + panic!() + } +} diff --git a/tests/debuginfo/collapse-debuginfo-external-attr.rs b/tests/debuginfo/collapse-debuginfo-external-attr.rs index fba609bf89e60..4d4fa92726f8e 100644 --- a/tests/debuginfo/collapse-debuginfo-external-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-external-attr.rs @@ -1,5 +1,4 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that local macro debug info is not collapsed with #[collapse_debuginfo(external)] diff --git a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs index 51aa1f8ce19e5..ab0ae8fef4df7 100644 --- a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that macro attribute #[collapse_debuginfo(no)] // overrides "collapse_macro_debuginfo=external" flag -//@ compile-flags:-g -Z collapse_macro_debuginfo=external +//@ compile-flags:-g -C collapse_macro_debuginfo=external // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-external-flag.rs b/tests/debuginfo/collapse-debuginfo-external-flag.rs index f9ef1ae8a258c..b8e73d227b365 100644 --- a/tests/debuginfo/collapse-debuginfo-external-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-external-flag.rs @@ -1,9 +1,8 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that println macro debug info is collapsed with "collapse_macro_debuginfo=external" flag -//@ compile-flags:-g -Z collapse_macro_debuginfo=external +//@ compile-flags:-g -C collapse_macro_debuginfo=external // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs index e67e1d83cdc97..1aafcffa30472 100644 --- a/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs +++ b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs @@ -1,11 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. // When nested macros instantiations are tagged with collapse_debuginfo attribute, // debug info should be corrected to the first outer macro instantiation // without collapse_debuginfo attribute. -// collapse_debuginfo feature enabled. //@ compile-flags:-g @@ -61,7 +59,7 @@ fn myprintln_impl(text: &str) { println!("{}", text) } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! myprintln { ($($arg:tt)*) => {{ myprintln_impl($($arg)*); diff --git a/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs b/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs deleted file mode 100644 index fbc7d03e0df8a..0000000000000 --- a/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ ignore-lldb -#![feature(collapse_debuginfo)] - -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` is active, `-Zdebug-macros` is provided and `#[collapse_debuginfo]` not -// being used. - -//@ compile-flags:-g -Zdebug-macros - -// === GDB TESTS =================================================================================== - -// gdb-command:run -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc1[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc2[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc3[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc4[...] -// gdb-command:continue - -fn one() { - println!("one"); -} -fn two() { - println!("two"); -} -fn three() { - println!("three"); -} -fn four() { - println!("four"); -} - -macro_rules! outer { - ($b:block) => { - one(); // #loc1 - inner!(); - $b - }; -} - -macro_rules! inner { - () => { - two(); // #loc2 - }; -} - -fn main() { - let ret = 0; // #break - outer!({ - three(); // #loc3 - four(); // #loc4 - }); - std::process::exit(ret); -} diff --git a/tests/debuginfo/collapse-debuginfo-no-attr.rs b/tests/debuginfo/collapse-debuginfo-no-attr.rs index 4ea1b2cf7a4e8..6f0d041024f4a 100644 --- a/tests/debuginfo/collapse-debuginfo-no-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-no-attr.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` feature is active and the attribute is not provided. +// Test that line numbers are not replaced with those of the outermost expansion site when +// `#[collapse_debuginfo]` attribute us not used. -//@ compile-flags:-g -Z collapse_macro_debuginfo=no +//@ compile-flags:-g // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs b/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs index b585cdf13e09e..8da084126ca06 100644 --- a/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs @@ -1,11 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` is active and `-Zdebug-macros` is provided, despite `#[collapse_debuginfo]` -// being used. +// Test that line numbers are not replaced with those of the outermost expansion site when +// `-C collapse-macro-debuginfo=false` is passed, despite `#[collapse_debuginfo]` being used. -//@ compile-flags:-g -Zdebug-macros +//@ compile-flags:-g -C collapse-macro-debuginfo=false // === GDB TESTS =================================================================================== @@ -37,7 +35,7 @@ fn four() { println!("four"); } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! outer { ($b:block) => { one(); // #loc1 @@ -46,7 +44,7 @@ macro_rules! outer { }; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! inner { () => { two(); // #loc2 diff --git a/tests/debuginfo/collapse-debuginfo-with-attr.rs b/tests/debuginfo/collapse-debuginfo-with-attr.rs index e7698c5f62991..fa66468779657 100644 --- a/tests/debuginfo/collapse-debuginfo-with-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-with-attr.rs @@ -1,5 +1,4 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that line numbers are replaced with those of the outermost expansion site when the // `collapse_debuginfo` feature is active and the attribute is provided. @@ -33,7 +32,7 @@ fn four() { println!("four"); } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! outer { ($b:block) => { one(); @@ -42,7 +41,7 @@ macro_rules! outer { }; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! inner { () => { two(); diff --git a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs index 2c3ecf3f5afbc..ef92f87ef4688 100644 --- a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that line numbers are replaced with those of the outermost expansion site when the -// `collapse_debuginfo` feature is active and the command line flag is provided. +// the command line flag is passed. -//@ compile-flags:-g -Z collapse_macro_debuginfo=yes +//@ compile-flags:-g -C collapse_macro_debuginfo=yes // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/coroutine-locals.rs b/tests/debuginfo/coroutine-locals.rs index 54b5cd577c8b9..c019998040b93 100644 --- a/tests/debuginfo/coroutine-locals.rs +++ b/tests/debuginfo/coroutine-locals.rs @@ -46,7 +46,7 @@ // lldb-command:v c // lldb-check:(int) c = 6 -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -54,7 +54,8 @@ use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let c = 6; // Live across multiple yield points let d = 7; // Live across only one yield point @@ -76,4 +77,6 @@ fn main() { _zzz(); // #break } -fn _zzz() {()} +fn _zzz() { + () +} diff --git a/tests/debuginfo/coroutine-objects.rs b/tests/debuginfo/coroutine-objects.rs index 9e1bd5d62e7a1..e13f20455a864 100644 --- a/tests/debuginfo/coroutine-objects.rs +++ b/tests/debuginfo/coroutine-objects.rs @@ -63,7 +63,7 @@ // cdb-check: b : Returned [Type: enum2$] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -71,7 +71,8 @@ use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let mut c = 6; let mut d = 7; diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index 1e4be43244554..2b0c2593676b4 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -83,7 +83,7 @@ #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] -#![feature(adt_const_params, coroutines, coroutine_trait)] +#![feature(adt_const_params, coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(incomplete_features)] use std::ops::Coroutine; @@ -111,7 +111,8 @@ fn main() { closure(); // Coroutine - let mut coroutine = || { + let mut coroutine = #[coroutine] + || { yield; return; }; diff --git a/tests/debuginfo/issue-57822.rs b/tests/debuginfo/issue-57822.rs index 93e1a2558f693..995779a6a9ca8 100644 --- a/tests/debuginfo/issue-57822.rs +++ b/tests/debuginfo/issue-57822.rs @@ -26,7 +26,7 @@ // lldb-command:v b // lldbg-check:(issue_57822::main::{coroutine_env#3}) b = -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -38,11 +38,13 @@ fn main() { let g = move || f(); let mut y = 2; - let mut a = move || { + let mut a = #[coroutine] + move || { y += 1; yield; }; - let mut b = move || { + let mut b = #[coroutine] + move || { Pin::new(&mut a).resume(()); yield; }; diff --git a/tests/debuginfo/lexical-scope-with-macro.rs b/tests/debuginfo/lexical-scope-with-macro.rs index 76c923524fb58..7ea3dc62e4503 100644 --- a/tests/debuginfo/lexical-scope-with-macro.rs +++ b/tests/debuginfo/lexical-scope-with-macro.rs @@ -1,7 +1,7 @@ //@ min-lldb-version: 310 //@ ignore-lldb FIXME #48807 -//@ compile-flags:-g -Zdebug-macros +//@ compile-flags:-g // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 71ff9798079fa..5f8d82871681f 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -87,6 +87,7 @@ extern crate macro_stepping; // exports new_scope!() // lldb-command:frame select // lldb-check:[...] #inc-loc3 [...] +#[collapse_debuginfo(yes)] macro_rules! foo { () => { let a = 1; opaque(a); @@ -95,6 +96,7 @@ macro_rules! foo { }; } +#[collapse_debuginfo(yes)] macro_rules! foo2 { () => { foo!(); diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index cfac14a22c418..0293ec0ec3975 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -132,7 +132,6 @@ // cdb-command: dx -r2 arbitrary_discr2,d // cdb-check: arbitrary_discr2,d : Def [Type: enum2$] // cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int] -#![feature(generic_nonzero)] #![feature(rustc_attrs)] #![feature(repr128)] #![feature(arbitrary_enum_discriminant)] diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index 1ff72d34fbdf2..98bc31e88557a 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -237,7 +237,6 @@ // lldb-command:v nz_usize // lldb-check:[...] 122 { __0 = { 0 = 122 } } -#![feature(generic_nonzero)] use std::num::*; use std::sync::atomic::*; diff --git a/tests/debuginfo/skip_second_statement.rs b/tests/debuginfo/skip_second_statement.rs index e0f3325bcff55..ba182de038543 100644 --- a/tests/debuginfo/skip_second_statement.rs +++ b/tests/debuginfo/skip_second_statement.rs @@ -2,9 +2,8 @@ // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. // Performed step-over and step-into debug stepping through call statements. -// collapse_debuginfo feature disabled. -//@ compile-flags:-g +//@ compile-flags:-g -C collapse-macro-debuginfo=yes // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/skip_second_statement_collapse.rs b/tests/debuginfo/skip_second_statement_collapse.rs index f1a74b629e48e..db90cee8bfba8 100644 --- a/tests/debuginfo/skip_second_statement_collapse.rs +++ b/tests/debuginfo/skip_second_statement_collapse.rs @@ -1,9 +1,7 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo // Performed step-over and step-into debug stepping through call statements. -// collapse_debuginfo feature enabled. //@ compile-flags:-g @@ -94,7 +92,7 @@ fn myprintln_impl(text: &str) { println!("{}", text) } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! myprintln { ($($arg:tt)*) => {{ myprintln_impl($($arg)*); diff --git a/tests/incremental/slice-pattern-const-ice-83085.rs b/tests/incremental/slice-pattern-const-ice-83085.rs new file mode 100644 index 0000000000000..4d318fd7ec18a --- /dev/null +++ b/tests/incremental/slice-pattern-const-ice-83085.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Zincremental-verify-ich=yes +// issue: rust-lang/rust#83085 incremental ICE: forcing query with already existing `DepNode` +// this used to fail to build straight away without needing any kind of +// stage1/2 builds but tidy demands it +//@ revisions:rpass1 rpass2 + +fn main() { + const BOO: &[u8; 0] = &[]; + match &[] { + BOO => (), + b"" => (), + _ => (), + } +} + +#[derive(PartialEq, Eq)] +struct Id<'a> { + ns: &'a str, +} +fn visit_struct() { + let id = Id { ns: "random1" }; + const FLAG: Id<'static> = Id { + ns: "needs_to_be_the_same", + }; + match id { + FLAG => {} + _ => {} + } +} +fn visit_struct2() { + let id = Id { ns: "random2" }; + const FLAG: Id<'static> = Id { + ns: "needs_to_be_the_same", + }; + match id { + FLAG => {} + _ => {} + } +} diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs index fe6abc546879c..e9a53b7aacb76 100644 --- a/tests/mir-opt/building/custom/arrays.rs +++ b/tests/mir-opt/building/custom/arrays.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; diff --git a/tests/mir-opt/building/custom/consts.rs b/tests/mir-opt/building/custom/consts.rs index 42abf5019e559..1a410177fa549 100644 --- a/tests/mir-opt/building/custom/consts.rs +++ b/tests/mir-opt/building/custom/consts.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs index bc72ed8dfe393..eb97bcc73b7e1 100644 --- a/tests/mir-opt/building/custom/operators.rs +++ b/tests/mir-opt/building/custom/operators.rs @@ -1,6 +1,6 @@ // skip-filecheck //@ compile-flags: --crate-type=lib -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] use std::intrinsics::mir::*; // EMIT_MIR operators.f.built.after.mir diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir index 194afdf7dd8a8..bade0fa4b45c8 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir @@ -4,8 +4,8 @@ fn full_tested_match() -> () { let mut _0: (); let mut _1: (i32, i32); let mut _2: std::option::Option; - let mut _3: isize; - let mut _4: &std::option::Option; + let mut _3: &std::option::Option; + let mut _4: isize; let _5: i32; let _6: &i32; let mut _7: bool; @@ -27,8 +27,8 @@ fn full_tested_match() -> () { StorageLive(_2); _2 = Option::::Some(const 42_i32); PlaceMention(_2); - _3 = discriminant(_2); - switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1]; + _4 = discriminant(_2); + switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; } bb1: { @@ -60,7 +60,7 @@ fn full_tested_match() -> () { bb7: { StorageLive(_6); _6 = &((_2 as Some).0: i32); - _4 = &fake _2; + _3 = &fake shallow _2; StorageLive(_7); _7 = guard() -> [return: bb8, unwind: bb16]; } @@ -71,7 +71,7 @@ fn full_tested_match() -> () { bb9: { StorageDead(_7); - FakeRead(ForMatchGuard, _4); + FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); StorageLive(_5); _5 = ((_2 as Some).0: i32); diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir index ae83075434f7b..0d78bb8b23587 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir @@ -4,8 +4,8 @@ fn full_tested_match2() -> () { let mut _0: (); let mut _1: (i32, i32); let mut _2: std::option::Option; - let mut _3: isize; - let mut _4: &std::option::Option; + let mut _3: &std::option::Option; + let mut _4: isize; let _5: i32; let _6: &i32; let mut _7: bool; @@ -27,8 +27,8 @@ fn full_tested_match2() -> () { StorageLive(_2); _2 = Option::::Some(const 42_i32); PlaceMention(_2); - _3 = discriminant(_2); - switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1]; + _4 = discriminant(_2); + switchInt(move _4) -> [0: bb5, 1: bb2, otherwise: bb1]; } bb1: { @@ -66,7 +66,7 @@ fn full_tested_match2() -> () { bb7: { StorageLive(_6); _6 = &((_2 as Some).0: i32); - _4 = &fake _2; + _3 = &fake shallow _2; StorageLive(_7); _7 = guard() -> [return: bb8, unwind: bb16]; } @@ -77,7 +77,7 @@ fn full_tested_match2() -> () { bb9: { StorageDead(_7); - FakeRead(ForMatchGuard, _4); + FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); StorageLive(_5); _5 = ((_2 as Some).0: i32); diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index dfa31cfff6b2c..ebb75ae141a33 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -4,9 +4,9 @@ fn main() -> () { let mut _0: (); let mut _1: i32; let mut _2: std::option::Option; - let mut _3: isize; + let mut _3: &std::option::Option; let mut _4: isize; - let mut _5: &std::option::Option; + let mut _5: isize; let _6: i32; let _7: &i32; let mut _8: bool; @@ -38,8 +38,8 @@ fn main() -> () { StorageLive(_2); _2 = Option::::Some(const 1_i32); PlaceMention(_2); - _4 = discriminant(_2); - switchInt(move _4) -> [1: bb8, otherwise: bb2]; + _5 = discriminant(_2); + switchInt(move _5) -> [1: bb8, otherwise: bb2]; } bb1: { @@ -52,8 +52,8 @@ fn main() -> () { } bb3: { - _3 = discriminant(_2); - switchInt(move _3) -> [1: bb6, otherwise: bb4]; + _4 = discriminant(_2); + switchInt(move _4) -> [1: bb6, otherwise: bb4]; } bb4: { @@ -87,7 +87,7 @@ fn main() -> () { bb10: { StorageLive(_7); _7 = &((_2 as Some).0: i32); - _5 = &fake _2; + _3 = &fake shallow _2; StorageLive(_8); _8 = guard() -> [return: bb11, unwind: bb24]; } @@ -98,7 +98,7 @@ fn main() -> () { bb12: { StorageDead(_8); - FakeRead(ForMatchGuard, _5); + FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _7); StorageLive(_6); _6 = ((_2 as Some).0: i32); @@ -129,7 +129,7 @@ fn main() -> () { bb16: { StorageLive(_11); _11 = &((_2 as Some).0: i32); - _5 = &fake _2; + _3 = &fake shallow _2; StorageLive(_12); StorageLive(_13); _13 = (*_11); @@ -143,7 +143,7 @@ fn main() -> () { bb18: { StorageDead(_13); StorageDead(_12); - FakeRead(ForMatchGuard, _5); + FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _11); StorageLive(_10); _10 = ((_2 as Some).0: i32); diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index c3497c6989d77..060cd6132e3a0 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -7,10 +7,10 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { let mut _3: (&str, bool); let mut _4: &str; let mut _5: bool; - let mut _6: bool; - let mut _7: bool; - let mut _8: &&str; - let mut _9: &bool; + let mut _6: &&str; + let mut _7: &bool; + let mut _8: bool; + let mut _9: bool; let mut _10: bool; bb0: { @@ -23,7 +23,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { StorageDead(_5); StorageDead(_4); PlaceMention(_3); - _7 = ::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19]; + _9 = ::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19]; } bb1: { @@ -52,7 +52,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb7: { - _6 = ::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19]; + _8 = ::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19]; } bb8: { @@ -64,16 +64,16 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb10: { - switchInt(move _6) -> [0: bb1, otherwise: bb8]; + switchInt(move _8) -> [0: bb1, otherwise: bb8]; } bb11: { - switchInt(move _7) -> [0: bb7, otherwise: bb4]; + switchInt(move _9) -> [0: bb7, otherwise: bb4]; } bb12: { - _8 = &fake (_3.0: &str); - _9 = &fake (_3.1: bool); + _6 = &fake shallow (_3.0: &str); + _7 = &fake shallow (_3.1: bool); StorageLive(_10); _10 = const true; switchInt(move _10) -> [0: bb14, otherwise: bb13]; @@ -81,8 +81,8 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { bb13: { StorageDead(_10); - FakeRead(ForMatchGuard, _8); - FakeRead(ForMatchGuard, _9); + FakeRead(ForMatchGuard, _6); + FakeRead(ForMatchGuard, _7); _0 = const 1_u32; goto -> bb18; } diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir index 4a1e4fb9ec56f..07daa3eddfa2c 100644 --- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir @@ -4,17 +4,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { debug x => _1; debug b => _2; let mut _0: u32; - let mut _3: bool; + let mut _3: &i32; let mut _4: bool; let mut _5: bool; let mut _6: bool; - let mut _7: &i32; + let mut _7: bool; let mut _8: bool; bb0: { PlaceMention(_1); - _5 = Le(const 0_i32, _1); - switchInt(move _5) -> [0: bb3, otherwise: bb8]; + _6 = Le(const 0_i32, _1); + switchInt(move _6) -> [0: bb3, otherwise: bb8]; } bb1: { @@ -27,8 +27,8 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb3: { - _3 = Le(const 10_i32, _1); - switchInt(move _3) -> [0: bb5, otherwise: bb7]; + _4 = Le(const 10_i32, _1); + switchInt(move _4) -> [0: bb5, otherwise: bb7]; } bb4: { @@ -44,17 +44,17 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb7: { - _4 = Le(_1, const 20_i32); - switchInt(move _4) -> [0: bb5, otherwise: bb4]; + _5 = Le(_1, const 20_i32); + switchInt(move _5) -> [0: bb5, otherwise: bb4]; } bb8: { - _6 = Lt(_1, const 10_i32); - switchInt(move _6) -> [0: bb3, otherwise: bb2]; + _7 = Lt(_1, const 10_i32); + switchInt(move _7) -> [0: bb3, otherwise: bb2]; } bb9: { - _7 = &fake _1; + _3 = &fake shallow _1; StorageLive(_8); _8 = _2; switchInt(move _8) -> [0: bb11, otherwise: bb10]; @@ -62,7 +62,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { bb10: { StorageDead(_8); - FakeRead(ForMatchGuard, _7); + FakeRead(ForMatchGuard, _3); _0 = const 0_u32; goto -> bb14; } diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index afd8746af5fb4..2b7271f63ff2f 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -4,7 +4,6 @@ // Verify that we can pretty print invalid constants. #![feature(adt_const_params)] -#![feature(inline_const)] #![allow(incomplete_features)] #[derive(Copy, Clone)] diff --git a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff index 5d94797905db4..77a2c5bcccc72 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff @@ -4,33 +4,26 @@ fn concrete() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; - let mut _10: usize; - let mut _12: usize; - let mut _14: usize; scope 1 { debug x => _1; - let _3: usize; + let _2: usize; scope 2 { - debug y => _3; - let _5: usize; + debug y => _2; + let _3: usize; scope 3 { - debug z0 => _5; - let _7: usize; + debug z0 => _3; + let _4: usize; scope 4 { - debug z1 => _7; - let _9: usize; + debug z1 => _4; + let _5: usize; scope 5 { - debug eA0 => _9; - let _11: usize; + debug eA0 => _5; + let _6: usize; scope 6 { - debug eA1 => _11; - let _13: usize; + debug eA1 => _6; + let _7: usize; scope 7 { - debug eC => _13; + debug eC => _7; } } } @@ -41,82 +34,33 @@ bb0: { StorageLive(_1); +- _1 = OffsetOf(Alpha, [(0, 0)]); ++ _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 0)]); -- _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; -+ _2 = const 4_usize; -+ _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); +- _2 = OffsetOf(Alpha, [(0, 1)]); ++ _2 = const 0_usize; StorageLive(_3); +- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); ++ _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 1)]); -- _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; -+ _4 = const 0_usize; -+ _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; - } - - bb2: { - StorageDead(_4); +- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); ++ _4 = const 3_usize; StorageLive(_5); +- _5 = OffsetOf(Epsilon, [(0, 0)]); ++ _5 = const 1_usize; StorageLive(_6); -- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; +- _6 = OffsetOf(Epsilon, [(0, 1)]); + _6 = const 2_usize; -+ _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; - } - - bb3: { - StorageDead(_6); StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; -+ _8 = const 3_usize; -+ _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; - } - - bb4: { - StorageDead(_8); - StorageLive(_9); - StorageLive(_10); -- _10 = OffsetOf(Epsilon, [(0, 0)]); -- _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; -+ _10 = const 1_usize; -+ _9 = must_use::(const 1_usize) -> [return: bb5, unwind unreachable]; - } - - bb5: { - StorageDead(_10); - StorageLive(_11); - StorageLive(_12); -- _12 = OffsetOf(Epsilon, [(0, 1)]); -- _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; -+ _12 = const 2_usize; -+ _11 = must_use::(const 2_usize) -> [return: bb6, unwind unreachable]; - } - - bb6: { - StorageDead(_12); - StorageLive(_13); - StorageLive(_14); -- _14 = OffsetOf(Epsilon, [(2, 0)]); -- _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; -+ _14 = const 4_usize; -+ _13 = must_use::(const 4_usize) -> [return: bb7, unwind unreachable]; - } - - bb7: { - StorageDead(_14); +- _7 = OffsetOf(Epsilon, [(2, 0)]); ++ _7 = const 4_usize; _0 = const (); - StorageDead(_13); - StorageDead(_11); - StorageDead(_9); StorageDead(_7); + StorageDead(_6); StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff index 4d890742ee99c..77a2c5bcccc72 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff @@ -4,33 +4,26 @@ fn concrete() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; - let mut _10: usize; - let mut _12: usize; - let mut _14: usize; scope 1 { debug x => _1; - let _3: usize; + let _2: usize; scope 2 { - debug y => _3; - let _5: usize; + debug y => _2; + let _3: usize; scope 3 { - debug z0 => _5; - let _7: usize; + debug z0 => _3; + let _4: usize; scope 4 { - debug z1 => _7; - let _9: usize; + debug z1 => _4; + let _5: usize; scope 5 { - debug eA0 => _9; - let _11: usize; + debug eA0 => _5; + let _6: usize; scope 6 { - debug eA1 => _11; - let _13: usize; + debug eA1 => _6; + let _7: usize; scope 7 { - debug eC => _13; + debug eC => _7; } } } @@ -41,82 +34,33 @@ bb0: { StorageLive(_1); +- _1 = OffsetOf(Alpha, [(0, 0)]); ++ _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 0)]); -- _1 = must_use::(move _2) -> [return: bb1, unwind continue]; -+ _2 = const 4_usize; -+ _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_2); +- _2 = OffsetOf(Alpha, [(0, 1)]); ++ _2 = const 0_usize; StorageLive(_3); +- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); ++ _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 1)]); -- _3 = must_use::(move _4) -> [return: bb2, unwind continue]; -+ _4 = const 0_usize; -+ _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; - } - - bb2: { - StorageDead(_4); +- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); ++ _4 = const 3_usize; StorageLive(_5); +- _5 = OffsetOf(Epsilon, [(0, 0)]); ++ _5 = const 1_usize; StorageLive(_6); -- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; +- _6 = OffsetOf(Epsilon, [(0, 1)]); + _6 = const 2_usize; -+ _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; - } - - bb3: { - StorageDead(_6); StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; -+ _8 = const 3_usize; -+ _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; - } - - bb4: { - StorageDead(_8); - StorageLive(_9); - StorageLive(_10); -- _10 = OffsetOf(Epsilon, [(0, 0)]); -- _9 = must_use::(move _10) -> [return: bb5, unwind continue]; -+ _10 = const 1_usize; -+ _9 = must_use::(const 1_usize) -> [return: bb5, unwind continue]; - } - - bb5: { - StorageDead(_10); - StorageLive(_11); - StorageLive(_12); -- _12 = OffsetOf(Epsilon, [(0, 1)]); -- _11 = must_use::(move _12) -> [return: bb6, unwind continue]; -+ _12 = const 2_usize; -+ _11 = must_use::(const 2_usize) -> [return: bb6, unwind continue]; - } - - bb6: { - StorageDead(_12); - StorageLive(_13); - StorageLive(_14); -- _14 = OffsetOf(Epsilon, [(2, 0)]); -- _13 = must_use::(move _14) -> [return: bb7, unwind continue]; -+ _14 = const 4_usize; -+ _13 = must_use::(const 4_usize) -> [return: bb7, unwind continue]; - } - - bb7: { - StorageDead(_14); +- _7 = OffsetOf(Epsilon, [(2, 0)]); ++ _7 = const 4_usize; _0 = const (); - StorageDead(_13); - StorageDead(_11); - StorageDead(_9); StorageDead(_7); + StorageDead(_6); StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff index 025241dd1bf96..130c31eff8ccc 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff @@ -4,33 +4,26 @@ fn generic() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; - let mut _10: usize; - let mut _12: usize; - let mut _14: usize; scope 1 { debug gx => _1; - let _3: usize; + let _2: usize; scope 2 { - debug gy => _3; - let _5: usize; + debug gy => _2; + let _3: usize; scope 3 { - debug dx => _5; - let _7: usize; + debug dx => _3; + let _4: usize; scope 4 { - debug dy => _7; - let _9: usize; + debug dy => _4; + let _5: usize; scope 5 { - debug zA0 => _9; - let _11: usize; + debug zA0 => _5; + let _6: usize; scope 6 { - debug zA1 => _11; - let _13: usize; + debug zA1 => _6; + let _7: usize; scope 7 { - debug zB => _13; + debug zB => _7; } } } @@ -41,72 +34,28 @@ bb0: { StorageLive(_1); + _1 = OffsetOf(Gamma, [(0, 0)]); StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); + _2 = OffsetOf(Gamma, [(0, 1)]); StorageLive(_3); +- _3 = OffsetOf(Delta, [(0, 1)]); ++ _3 = const 0_usize; StorageLive(_4); - _4 = OffsetOf(Gamma, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; - } - - bb2: { - StorageDead(_4); +- _4 = OffsetOf(Delta, [(0, 2)]); ++ _4 = const 2_usize; StorageLive(_5); + _5 = OffsetOf(Zeta, [(0, 0)]); StorageLive(_6); -- _6 = OffsetOf(Delta, [(0, 1)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; -+ _6 = const 0_usize; -+ _5 = must_use::(const 0_usize) -> [return: bb3, unwind unreachable]; - } - - bb3: { - StorageDead(_6); + _6 = OffsetOf(Zeta, [(0, 1)]); StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Delta, [(0, 2)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; -+ _8 = const 2_usize; -+ _7 = must_use::(const 2_usize) -> [return: bb4, unwind unreachable]; - } - - bb4: { - StorageDead(_8); - StorageLive(_9); - StorageLive(_10); - _10 = OffsetOf(Zeta, [(0, 0)]); - _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; - } - - bb5: { - StorageDead(_10); - StorageLive(_11); - StorageLive(_12); - _12 = OffsetOf(Zeta, [(0, 1)]); - _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; - } - - bb6: { - StorageDead(_12); - StorageLive(_13); - StorageLive(_14); - _14 = OffsetOf(Zeta, [(1, 0)]); - _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; - } - - bb7: { - StorageDead(_14); + _7 = OffsetOf(Zeta, [(1, 0)]); _0 = const (); - StorageDead(_13); - StorageDead(_11); - StorageDead(_9); StorageDead(_7); + StorageDead(_6); StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff index 27f2b2f7355ed..130c31eff8ccc 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff @@ -4,33 +4,26 @@ fn generic() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; - let mut _10: usize; - let mut _12: usize; - let mut _14: usize; scope 1 { debug gx => _1; - let _3: usize; + let _2: usize; scope 2 { - debug gy => _3; - let _5: usize; + debug gy => _2; + let _3: usize; scope 3 { - debug dx => _5; - let _7: usize; + debug dx => _3; + let _4: usize; scope 4 { - debug dy => _7; - let _9: usize; + debug dy => _4; + let _5: usize; scope 5 { - debug zA0 => _9; - let _11: usize; + debug zA0 => _5; + let _6: usize; scope 6 { - debug zA1 => _11; - let _13: usize; + debug zA1 => _6; + let _7: usize; scope 7 { - debug zB => _13; + debug zB => _7; } } } @@ -41,72 +34,28 @@ bb0: { StorageLive(_1); + _1 = OffsetOf(Gamma, [(0, 0)]); StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_2); + _2 = OffsetOf(Gamma, [(0, 1)]); StorageLive(_3); +- _3 = OffsetOf(Delta, [(0, 1)]); ++ _3 = const 0_usize; StorageLive(_4); - _4 = OffsetOf(Gamma, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind continue]; - } - - bb2: { - StorageDead(_4); +- _4 = OffsetOf(Delta, [(0, 2)]); ++ _4 = const 2_usize; StorageLive(_5); + _5 = OffsetOf(Zeta, [(0, 0)]); StorageLive(_6); -- _6 = OffsetOf(Delta, [(0, 1)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; -+ _6 = const 0_usize; -+ _5 = must_use::(const 0_usize) -> [return: bb3, unwind continue]; - } - - bb3: { - StorageDead(_6); + _6 = OffsetOf(Zeta, [(0, 1)]); StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Delta, [(0, 2)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; -+ _8 = const 2_usize; -+ _7 = must_use::(const 2_usize) -> [return: bb4, unwind continue]; - } - - bb4: { - StorageDead(_8); - StorageLive(_9); - StorageLive(_10); - _10 = OffsetOf(Zeta, [(0, 0)]); - _9 = must_use::(move _10) -> [return: bb5, unwind continue]; - } - - bb5: { - StorageDead(_10); - StorageLive(_11); - StorageLive(_12); - _12 = OffsetOf(Zeta, [(0, 1)]); - _11 = must_use::(move _12) -> [return: bb6, unwind continue]; - } - - bb6: { - StorageDead(_12); - StorageLive(_13); - StorageLive(_14); - _14 = OffsetOf(Zeta, [(1, 0)]); - _13 = must_use::(move _14) -> [return: bb7, unwind continue]; - } - - bb7: { - StorageDead(_14); + _7 = OffsetOf(Zeta, [(1, 0)]); _0 = const (); - StorageDead(_13); - StorageDead(_11); - StorageDead(_9); StorageDead(_7); + StorageDead(_6); StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir index 7214b01c60164..7e033916fd348 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { +fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () { let mut _0: (); let mut _2: (); let _3: std::string::String; diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir index 00769a493b5a1..613ef2909b5e4 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { +fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () { let mut _0: (); let mut _2: (); let _3: std::string::String; diff --git a/tests/mir-opt/coroutine_drop_cleanup.rs b/tests/mir-opt/coroutine_drop_cleanup.rs index 69984c737fed6..33fdd2dd0d9cb 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.rs +++ b/tests/mir-opt/coroutine_drop_cleanup.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -8,7 +8,8 @@ // EMIT_MIR coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.mir fn main() { - let gen = || { + let gen = #[coroutine] + || { let _s = String::new(); yield; }; diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir index 8369a3e60dd9a..4731aed335d9f 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () +fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> () yields () { let mut _0: (); diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir index 1773db1abffe3..14e1782b86016 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () +fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> () yields () { let mut _0: (); diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.rs b/tests/mir-opt/coroutine_storage_dead_unwind.rs index 253be1ff698d1..ce9bad483af83 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.rs +++ b/tests/mir-opt/coroutine_storage_dead_unwind.rs @@ -6,7 +6,7 @@ // Basic block and local names can safely change, but the StorageDead statements // should not go away. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] struct Foo(i32); @@ -20,7 +20,8 @@ fn take(_x: T) {} // EMIT_MIR coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir fn main() { - let _gen = || { + let _gen = #[coroutine] + || { let a = Foo(5); let b = Bar(6); yield; diff --git a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir index 165aa3a05cb7d..f8b3f68d21e63 100644 --- a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir @@ -4,7 +4,7 @@ _0: CoroutineSavedTy { ty: HasDrop, source_info: SourceInfo { - span: $DIR/coroutine_tiny.rs:21:13: 21:15 (#0), + span: $DIR/coroutine_tiny.rs:22:13: 22:15 (#0), scope: scope[0], }, ignore_for_traits: false, @@ -21,7 +21,7 @@ }, } */ -fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}>, _2: u8) -> CoroutineState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}>, _2: u8) -> CoroutineState<(), ()> { debug _x => _10; let mut _0: std::ops::CoroutineState<(), ()>; let _3: HasDrop; @@ -34,18 +34,18 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24 let _10: u8; let mut _11: u32; scope 1 { - debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop); + debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop); } bb0: { - _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))); + _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))); switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6]; } bb1: { _10 = move _2; nop; - (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop) = HasDrop; + (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop; StorageLive(_4); goto -> bb2; } @@ -58,7 +58,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24 StorageDead(_4); StorageDead(_6); StorageDead(_7); - discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))) = 3; + discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))) = 3; return; } diff --git a/tests/mir-opt/coroutine_tiny.rs b/tests/mir-opt/coroutine_tiny.rs index 9728425f2326e..81e9940541ba0 100644 --- a/tests/mir-opt/coroutine_tiny.rs +++ b/tests/mir-opt/coroutine_tiny.rs @@ -5,7 +5,7 @@ //@ compile-flags: -C panic=abort //@ no-prefer-dynamic -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] struct HasDrop; @@ -17,7 +17,8 @@ fn callee() {} // EMIT_MIR coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir fn main() { - let _gen = |_x: u8| { + let _gen = #[coroutine] + |_x: u8| { let _d = HasDrop; loop { yield; diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff new file mode 100644 index 0000000000000..e60f71f47b1ed --- /dev/null +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -0,0 +1,138 @@ +- // MIR for `main` before InstrumentCoverage ++ // MIR for `main` after InstrumentCoverage + + fn main() -> () { + let mut _0: (); + let mut _1: Enum; + let mut _2: isize; + let _3: u32; + let mut _4: u32; + let _5: u32; + let mut _6: u32; + let _7: u32; + let mut _8: u32; + let _9: u32; + let mut _10: u32; + scope 1 { + debug d => _3; + } + scope 2 { + debug c => _5; + } + scope 3 { + debug b => _7; + } + scope 4 { + debug a => _9; + } + ++ coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; ++ coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; ++ coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; ++ coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; ++ coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; ++ coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; ++ coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; ++ coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; ++ coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; ++ coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33; ++ coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33; ++ coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2; ++ + bb0: { ++ Coverage::CounterIncrement(0); + StorageLive(_1); + _1 = Enum::A(const 0_u32); + PlaceMention(_1); + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { ++ Coverage::CounterIncrement(3); + falseEdge -> [real: bb6, imaginary: bb3]; + } + + bb3: { ++ Coverage::CounterIncrement(2); + falseEdge -> [real: bb8, imaginary: bb4]; + } + + bb4: { ++ Coverage::CounterIncrement(1); + falseEdge -> [real: bb10, imaginary: bb5]; + } + + bb5: { ++ Coverage::ExpressionUsed(2); + StorageLive(_9); + _9 = ((_1 as A).0: u32); + StorageLive(_10); + _10 = _9; + _0 = consume(move _10) -> [return: bb12, unwind: bb14]; + } + + bb6: { + StorageLive(_3); + _3 = ((_1 as D).0: u32); + StorageLive(_4); + _4 = _3; + _0 = consume(move _4) -> [return: bb7, unwind: bb14]; + } + + bb7: { + StorageDead(_4); + StorageDead(_3); + goto -> bb13; + } + + bb8: { + StorageLive(_5); + _5 = ((_1 as C).0: u32); + StorageLive(_6); + _6 = _5; + _0 = consume(move _6) -> [return: bb9, unwind: bb14]; + } + + bb9: { + StorageDead(_6); + StorageDead(_5); + goto -> bb13; + } + + bb10: { + StorageLive(_7); + _7 = ((_1 as B).0: u32); + StorageLive(_8); + _8 = _7; + _0 = consume(move _8) -> [return: bb11, unwind: bb14]; + } + + bb11: { + StorageDead(_8); + StorageDead(_7); + goto -> bb13; + } + + bb12: { + StorageDead(_10); + StorageDead(_9); + goto -> bb13; + } + + bb13: { ++ Coverage::ExpressionUsed(5); + StorageDead(_1); + return; + } + + bb14 (cleanup): { + resume; + } + } + diff --git a/tests/mir-opt/coverage/branch_match_arms.rs b/tests/mir-opt/coverage/branch_match_arms.rs new file mode 100644 index 0000000000000..18764b38d6e3e --- /dev/null +++ b/tests/mir-opt/coverage/branch_match_arms.rs @@ -0,0 +1,27 @@ +#![feature(coverage_attribute)] +//@ test-mir-pass: InstrumentCoverage +//@ compile-flags: -Cinstrument-coverage -Zno-profiler-runtime -Zcoverage-options=branch +// skip-filecheck + +enum Enum { + A(u32), + B(u32), + C(u32), + D(u32), +} + +// EMIT_MIR branch_match_arms.main.InstrumentCoverage.diff +fn main() { + match Enum::A(0) { + Enum::D(d) => consume(d), + Enum::C(c) => consume(c), + Enum::B(b) => consume(b), + Enum::A(a) => consume(a), + } +} + +#[inline(never)] +#[coverage(off)] +fn consume(x: u32) { + core::hint::black_box(x); +} diff --git a/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff similarity index 100% rename from tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff rename to tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff diff --git a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff similarity index 100% rename from tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff rename to tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff diff --git a/tests/mir-opt/instrument_coverage.rs b/tests/mir-opt/coverage/instrument_coverage.rs similarity index 100% rename from tests/mir-opt/instrument_coverage.rs rename to tests/mir-opt/coverage/instrument_coverage.rs diff --git a/tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff similarity index 100% rename from tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff rename to tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff diff --git a/tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff similarity index 100% rename from tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff rename to tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff diff --git a/tests/mir-opt/instrument_coverage_cleanup.rs b/tests/mir-opt/coverage/instrument_coverage_cleanup.rs similarity index 100% rename from tests/mir-opt/instrument_coverage_cleanup.rs rename to tests/mir-opt/coverage/instrument_coverage_cleanup.rs diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff index f8f8917503370..92691d0f80703 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff @@ -4,21 +4,17 @@ fn concrete() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; scope 1 { debug x => _1; - let _3: usize; + let _2: usize; scope 2 { - debug y => _3; - let _5: usize; + debug y => _2; + let _3: usize; scope 3 { - debug z0 => _5; - let _7: usize; + debug z0 => _3; + let _4: usize; scope 4 { - debug z1 => _7; + debug z1 => _4; } } } @@ -26,49 +22,21 @@ bb0: { StorageLive(_1); +- _1 = OffsetOf(Alpha, [(0, 0)]); ++ _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 0)]); -- _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; -+ _2 = const 4_usize; -+ _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); +- _2 = OffsetOf(Alpha, [(0, 1)]); ++ _2 = const 0_usize; StorageLive(_3); +- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); ++ _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 1)]); -- _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; -+ _4 = const 0_usize; -+ _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; - } - - bb2: { - StorageDead(_4); - StorageLive(_5); - StorageLive(_6); -- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; -+ _6 = const 2_usize; -+ _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; - } - - bb3: { - StorageDead(_6); - StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; -+ _8 = const 3_usize; -+ _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; - } - - bb4: { - StorageDead(_8); +- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); ++ _4 = const 3_usize; _0 = const (); - StorageDead(_7); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff index d4f8cb66704ae..92691d0f80703 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff @@ -4,21 +4,17 @@ fn concrete() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; scope 1 { debug x => _1; - let _3: usize; + let _2: usize; scope 2 { - debug y => _3; - let _5: usize; + debug y => _2; + let _3: usize; scope 3 { - debug z0 => _5; - let _7: usize; + debug z0 => _3; + let _4: usize; scope 4 { - debug z1 => _7; + debug z1 => _4; } } } @@ -26,49 +22,21 @@ bb0: { StorageLive(_1); +- _1 = OffsetOf(Alpha, [(0, 0)]); ++ _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 0)]); -- _1 = must_use::(move _2) -> [return: bb1, unwind continue]; -+ _2 = const 4_usize; -+ _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_2); +- _2 = OffsetOf(Alpha, [(0, 1)]); ++ _2 = const 0_usize; StorageLive(_3); +- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); ++ _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 1)]); -- _3 = must_use::(move _4) -> [return: bb2, unwind continue]; -+ _4 = const 0_usize; -+ _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; - } - - bb2: { - StorageDead(_4); - StorageLive(_5); - StorageLive(_6); -- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; -+ _6 = const 2_usize; -+ _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; - } - - bb3: { - StorageDead(_6); - StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; -+ _8 = const 3_usize; -+ _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; - } - - bb4: { - StorageDead(_8); +- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); ++ _4 = const 3_usize; _0 = const (); - StorageDead(_7); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff index 7f166e4fa356a..c6908166defb8 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff @@ -4,21 +4,17 @@ fn generic() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; scope 1 { debug gx => _1; - let _3: usize; + let _2: usize; scope 2 { - debug gy => _3; - let _5: usize; + debug gy => _2; + let _3: usize; scope 3 { - debug dx => _5; - let _7: usize; + debug dx => _3; + let _4: usize; scope 4 { - debug dy => _7; + debug dy => _4; } } } @@ -26,45 +22,19 @@ bb0: { StorageLive(_1); + _1 = OffsetOf(Gamma, [(0, 0)]); StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); + _2 = OffsetOf(Gamma, [(0, 1)]); StorageLive(_3); +- _3 = OffsetOf(Delta, [(0, 1)]); ++ _3 = const 0_usize; StorageLive(_4); - _4 = OffsetOf(Gamma, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; - } - - bb2: { - StorageDead(_4); - StorageLive(_5); - StorageLive(_6); -- _6 = OffsetOf(Delta, [(0, 1)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; -+ _6 = const 0_usize; -+ _5 = must_use::(const 0_usize) -> [return: bb3, unwind unreachable]; - } - - bb3: { - StorageDead(_6); - StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Delta, [(0, 2)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; -+ _8 = const 2_usize; -+ _7 = must_use::(const 2_usize) -> [return: bb4, unwind unreachable]; - } - - bb4: { - StorageDead(_8); +- _4 = OffsetOf(Delta, [(0, 2)]); ++ _4 = const 2_usize; _0 = const (); - StorageDead(_7); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff index 38ad6f7980160..c6908166defb8 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff @@ -4,21 +4,17 @@ fn generic() -> () { let mut _0: (); let _1: usize; - let mut _2: usize; - let mut _4: usize; - let mut _6: usize; - let mut _8: usize; scope 1 { debug gx => _1; - let _3: usize; + let _2: usize; scope 2 { - debug gy => _3; - let _5: usize; + debug gy => _2; + let _3: usize; scope 3 { - debug dx => _5; - let _7: usize; + debug dx => _3; + let _4: usize; scope 4 { - debug dy => _7; + debug dy => _4; } } } @@ -26,45 +22,19 @@ bb0: { StorageLive(_1); + _1 = OffsetOf(Gamma, [(0, 0)]); StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_2); + _2 = OffsetOf(Gamma, [(0, 1)]); StorageLive(_3); +- _3 = OffsetOf(Delta, [(0, 1)]); ++ _3 = const 0_usize; StorageLive(_4); - _4 = OffsetOf(Gamma, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind continue]; - } - - bb2: { - StorageDead(_4); - StorageLive(_5); - StorageLive(_6); -- _6 = OffsetOf(Delta, [(0, 1)]); -- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; -+ _6 = const 0_usize; -+ _5 = must_use::(const 0_usize) -> [return: bb3, unwind continue]; - } - - bb3: { - StorageDead(_6); - StorageLive(_7); - StorageLive(_8); -- _8 = OffsetOf(Delta, [(0, 2)]); -- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; -+ _8 = const 2_usize; -+ _7 = must_use::(const 2_usize) -> [return: bb4, unwind continue]; - } - - bb4: { - StorageDead(_8); +- _4 = OffsetOf(Delta, [(0, 2)]); ++ _4 = const 2_usize; _0 = const (); - StorageDead(_7); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); + StorageDead(_2); StorageDead(_1); return; } diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs index cd4e1f6990dbb..12396b31ed0e9 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.rs +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -36,16 +36,16 @@ fn concrete() { // CHECK: debug z0 => [[z0:_.*]]; // CHECK: debug z1 => [[z1:_.*]]; - // CHECK: [[x]] = must_use::(const 4_usize) -> {{.*}} + // CHECK: [[x]] = const 4_usize let x = offset_of!(Alpha, x); - // CHECK: [[y]] = must_use::(const 0_usize) -> {{.*}} + // CHECK: [[y]] = const 0_usize let y = offset_of!(Alpha, y); - // CHECK: [[z0]] = must_use::(const 2_usize) -> {{.*}} + // CHECK: [[z0]] = const 2_usize let z0 = offset_of!(Alpha, z.0); - // CHECK: [[z1]] = must_use::(const 3_usize) -> {{.*}} + // CHECK: [[z1]] = const 3_usize let z1 = offset_of!(Alpha, z.1); } @@ -58,16 +58,16 @@ fn generic() { // CHECK: debug dx => [[dx:_.*]]; // CHECK: debug dy => [[dy:_.*]]; - // CHECK: [[gx]] = must_use::(move {{_.*}}) -> {{.*}} + // CHECK: [[gx]] = OffsetOf(Gamma, [(0, 0)]); let gx = offset_of!(Gamma, x); - // CHECK: [[gy]] = must_use::(move {{_.*}}) -> {{.*}} + // CHECK: [[gy]] = OffsetOf(Gamma, [(0, 1)]); let gy = offset_of!(Gamma, y); - // CHECK: [[dx]] = must_use::(const 0_usize) -> {{.*}} + // CHECK: [[dx]] = const 0_usize let dx = offset_of!(Delta, x); - // CHECK: [[dy]] = must_use::(const 2_usize) -> {{.*}} + // CHECK: [[dy]] = const 2_usize let dy = offset_of!(Delta, y); } diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 859082c311190..07031a298bc36 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -4,24 +4,24 @@ fn main() -> () { let mut _0: (); let _1: std::ops::CoroutineState; - let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; - let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; - let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>; + let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _5: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { + } -+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { ++ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; -+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { ++ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { + debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { + debug a => _5; -+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; ++ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _7: u32; + let mut _8: i32; + } @@ -32,22 +32,22 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind unreachable]; -+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; ++ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; + StorageLive(_6); + StorageLive(_7); -+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); ++ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); + switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; } bb1: { - _3 = &mut _4; -- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind unreachable]; +- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind unreachable]; + StorageDead(_4); + _0 = const (); + StorageDead(_1); @@ -56,7 +56,7 @@ bb2: { - StorageDead(_3); -- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine>::resume(move _2, const false) -> [return: bb3, unwind unreachable]; +- _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine>::resume(move _2, const false) -> [return: bb3, unwind unreachable]; + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 44b06c34972af..ab6c62b0baf56 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -4,24 +4,24 @@ fn main() -> () { let mut _0: (); let _1: std::ops::CoroutineState; - let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; - let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; - let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>; + let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _5: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { + } -+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { ++ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; -+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { ++ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { + debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { + debug a => _5; -+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; ++ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _7: u32; + let mut _8: i32; + } @@ -32,22 +32,22 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind continue]; -+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; ++ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; + StorageLive(_6); + StorageLive(_7); -+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); ++ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); + switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; } bb1: { - _3 = &mut _4; -- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind: bb5]; +- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind: bb5]; + StorageDead(_4); + _0 = const (); + StorageDead(_1); @@ -56,7 +56,7 @@ - bb2: { - StorageDead(_3); -- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; +- _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; + bb2 (cleanup): { + drop(_4) -> [return: bb3, unwind terminate(cleanup)]; } diff --git a/tests/mir-opt/inline/inline_coroutine.rs b/tests/mir-opt/inline/inline_coroutine.rs index 180f9d4a6fddd..07f8fb20f7ea2 100644 --- a/tests/mir-opt/inline/inline_coroutine.rs +++ b/tests/mir-opt/inline/inline_coroutine.rs @@ -16,5 +16,6 @@ fn main() { #[inline] pub fn g() -> impl Coroutine { #[inline] - |a| { yield if a { 7 } else { 13 } } + #[coroutine] + |a| yield if a { 7 } else { 13 } } diff --git a/tests/mir-opt/instsimplify/combine_transmutes.rs b/tests/mir-opt/instsimplify/combine_transmutes.rs index a1274dd1b4086..0be7466001fe2 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.rs +++ b/tests/mir-opt/instsimplify/combine_transmutes.rs @@ -3,7 +3,6 @@ #![crate_type = "lib"] #![feature(core_intrinsics)] #![feature(custom_mir)] -#![feature(generic_nonzero)] use std::intrinsics::mir::*; use std::mem::{MaybeUninit, ManuallyDrop, transmute}; diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index ba333ba1a5866..209f0d09c2943 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -80,8 +80,8 @@ _6 = &(_2.1: bool); StorageLive(_8); _8 = &(_2.2: std::string::String); -- _3 = &fake (_2.0: bool); -- _4 = &fake (_2.1: bool); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); StorageLive(_9); StorageLive(_10); _10 = _1; @@ -137,8 +137,8 @@ _6 = &(_2.0: bool); StorageLive(_8); _8 = &(_2.2: std::string::String); -- _3 = &fake (_2.0: bool); -- _4 = &fake (_2.1: bool); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); StorageLive(_12); StorageLive(_13); _13 = _1; diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index ba333ba1a5866..209f0d09c2943 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -80,8 +80,8 @@ _6 = &(_2.1: bool); StorageLive(_8); _8 = &(_2.2: std::string::String); -- _3 = &fake (_2.0: bool); -- _4 = &fake (_2.1: bool); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); StorageLive(_9); StorageLive(_10); _10 = _1; @@ -137,8 +137,8 @@ _6 = &(_2.0: bool); StorageLive(_8); _8 = &(_2.2: std::string::String); -- _3 = &fake (_2.0: bool); -- _4 = &fake (_2.1: bool); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); StorageLive(_12); StorageLive(_13); _13 = _1; diff --git a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff index 54da6ee659f95..d76d65a18a7b4 100644 --- a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff +++ b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff @@ -5,17 +5,17 @@ debug x => _1; debug c => _2; let mut _0: i32; - let mut _3: isize; - let mut _4: &std::option::Option<&&i32>; + let mut _3: &std::option::Option<&&i32>; + let mut _4: &i32; let mut _5: &&i32; let mut _6: &&&i32; - let mut _7: &i32; + let mut _7: isize; let mut _8: bool; bb0: { PlaceMention(_1); - _3 = discriminant(_1); - switchInt(move _3) -> [1: bb2, otherwise: bb1]; + _7 = discriminant(_1); + switchInt(move _7) -> [1: bb2, otherwise: bb1]; } bb1: { @@ -33,10 +33,10 @@ } bb4: { -- _4 = &fake _1; -- _5 = &fake (*((_1 as Some).0: &&i32)); -- _6 = &fake ((_1 as Some).0: &&i32); -- _7 = &fake (*(*((_1 as Some).0: &&i32))); +- _3 = &fake shallow _1; +- _4 = &fake shallow (*(*((_1 as Some).0: &&i32))); +- _5 = &fake shallow (*((_1 as Some).0: &&i32)); +- _6 = &fake shallow ((_1 as Some).0: &&i32); + nop; + nop; + nop; @@ -48,10 +48,10 @@ bb5: { StorageDead(_8); +- FakeRead(ForMatchGuard, _3); - FakeRead(ForMatchGuard, _4); - FakeRead(ForMatchGuard, _5); - FakeRead(ForMatchGuard, _6); -- FakeRead(ForMatchGuard, _7); + nop; + nop; + nop; diff --git a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff index 54da6ee659f95..d76d65a18a7b4 100644 --- a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff +++ b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff @@ -5,17 +5,17 @@ debug x => _1; debug c => _2; let mut _0: i32; - let mut _3: isize; - let mut _4: &std::option::Option<&&i32>; + let mut _3: &std::option::Option<&&i32>; + let mut _4: &i32; let mut _5: &&i32; let mut _6: &&&i32; - let mut _7: &i32; + let mut _7: isize; let mut _8: bool; bb0: { PlaceMention(_1); - _3 = discriminant(_1); - switchInt(move _3) -> [1: bb2, otherwise: bb1]; + _7 = discriminant(_1); + switchInt(move _7) -> [1: bb2, otherwise: bb1]; } bb1: { @@ -33,10 +33,10 @@ } bb4: { -- _4 = &fake _1; -- _5 = &fake (*((_1 as Some).0: &&i32)); -- _6 = &fake ((_1 as Some).0: &&i32); -- _7 = &fake (*(*((_1 as Some).0: &&i32))); +- _3 = &fake shallow _1; +- _4 = &fake shallow (*(*((_1 as Some).0: &&i32))); +- _5 = &fake shallow (*((_1 as Some).0: &&i32)); +- _6 = &fake shallow ((_1 as Some).0: &&i32); + nop; + nop; + nop; @@ -48,10 +48,10 @@ bb5: { StorageDead(_8); +- FakeRead(ForMatchGuard, _3); - FakeRead(ForMatchGuard, _4); - FakeRead(ForMatchGuard, _5); - FakeRead(ForMatchGuard, _6); -- FakeRead(ForMatchGuard, _7); + nop; + nop; + nop; diff --git a/tests/pretty/ast-stmt-expr-attr.rs b/tests/pretty/ast-stmt-expr-attr.rs index fd7272a1b1fd3..899f7173f704e 100644 --- a/tests/pretty/ast-stmt-expr-attr.rs +++ b/tests/pretty/ast-stmt-expr-attr.rs @@ -13,17 +13,17 @@ fn syntax() { let _ = #[attr] (); let _ = #[attr] (#[attr] 0,); let _ = #[attr] (#[attr] 0, 0); - let _ = #[attr] 0 + #[attr] 0; - let _ = #[attr] 0 / #[attr] 0; - let _ = #[attr] 0 & #[attr] 0; - let _ = #[attr] 0 % #[attr] 0; + let _ = (#[attr] 0) + #[attr] 0; + let _ = (#[attr] 0) / #[attr] 0; + let _ = (#[attr] 0) & #[attr] 0; + let _ = (#[attr] 0) % #[attr] 0; let _ = #[attr] (0 + 0); let _ = #[attr] !0; let _ = #[attr] -0; let _ = #[attr] false; let _ = #[attr] 0; let _ = #[attr] 'c'; - let _ = #[attr] x as Y; + let _ = (#[attr] x) as Y; let _ = #[attr] (x as Y); let _ = #[attr] while true { @@ -88,9 +88,9 @@ fn syntax() { let _ = (); foo }; - let _ = #[attr] x = y; + let _ = (#[attr] x) = y; let _ = #[attr] (x = y); - let _ = #[attr] x += y; + let _ = (#[attr] x) += y; let _ = #[attr] (x += y); let _ = #[attr] foo.bar; let _ = (#[attr] foo).bar; @@ -98,8 +98,8 @@ fn syntax() { let _ = (#[attr] foo).0; let _ = #[attr] foo[bar]; let _ = (#[attr] foo)[bar]; - let _ = #[attr] 0..#[attr] 0; - let _ = #[attr] 0..; + let _ = (#[attr] 0)..#[attr] 0; + let _ = (#[attr] 0)..; let _ = #[attr] (0..0); let _ = #[attr] (0..); let _ = #[attr] (..0); diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp new file mode 100644 index 0000000000000..967aa7bc39ef3 --- /dev/null +++ b/tests/pretty/postfix-match/precedence.pp @@ -0,0 +1,34 @@ +#![feature(prelude_import)] +#![no_std] +#![feature(postfix_match)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +use std::ops::Add; + +//@ pretty-mode:expanded +//@ pp-exact:precedence.pp + +macro_rules! repro { ($e:expr) => { $e.match { _ => {} } }; } + +struct Struct {} + +impl Add for usize { + type Output = (); + fn add(self, _: Struct) -> () { () } +} +pub fn main() { + let a; + ( + { 1 } + 1).match { + _ => {} + }; + (4 as usize).match { _ => {} }; + (return).match { _ => {} }; + (a = 42).match { _ => {} }; + (|| {}).match { _ => {} }; + (42..101).match { _ => {} }; + (1 + Struct {}).match { _ => {} }; +} diff --git a/tests/pretty/postfix-match/precedence.rs b/tests/pretty/postfix-match/precedence.rs new file mode 100644 index 0000000000000..ee947e161ddcf --- /dev/null +++ b/tests/pretty/postfix-match/precedence.rs @@ -0,0 +1,34 @@ +#![feature(postfix_match)] + +use std::ops::Add; + +//@ pretty-mode:expanded +//@ pp-exact:precedence.pp + +macro_rules! repro { + ($e:expr) => { + $e.match { + _ => {} + } + }; +} + +struct Struct {} + +impl Add for usize { + type Output = (); + fn add(self, _: Struct) -> () { + () + } +} +pub fn main() { + let a; + + repro!({ 1 } + 1); + repro!(4 as usize); + repro!(return); + repro!(a = 42); + repro!(|| {}); + repro!(42..101); + repro!(1 + Struct {}); +} diff --git a/tests/pretty/postfix-match.rs b/tests/pretty/postfix-match/simple-matches.rs similarity index 100% rename from tests/pretty/postfix-match.rs rename to tests/pretty/postfix-match/simple-matches.rs diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index 98ad98b863ac6..5eb7d2fcae36a 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -1,6 +1,5 @@ //@ pp-exact -#![feature(inline_const)] #![feature(inline_const_pat)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] @@ -148,13 +147,13 @@ fn _11() { let _ = #[rustc_dummy] (0); let _ = #[rustc_dummy] (0,); let _ = #[rustc_dummy] (0, 0); - let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0; + let _ = (#[rustc_dummy] 0) + #[rustc_dummy] 0; let _ = #[rustc_dummy] !0; let _ = #[rustc_dummy] -0i32; let _ = #[rustc_dummy] false; let _ = #[rustc_dummy] 'c'; let _ = #[rustc_dummy] 0; - let _ = #[rustc_dummy] 0 as usize; + let _ = (#[rustc_dummy] 0) as usize; let _ = #[rustc_dummy] while false { #![rustc_dummy] @@ -214,8 +213,8 @@ fn _11() { #![rustc_dummy] }; let mut x = 0; - let _ = #[rustc_dummy] x = 15; - let _ = #[rustc_dummy] x += 15; + let _ = (#[rustc_dummy] x) = 15; + let _ = (#[rustc_dummy] x) += 15; let s = Foo { data: () }; let _ = #[rustc_dummy] s.data; let _ = (#[rustc_dummy] s).data; @@ -225,8 +224,8 @@ fn _11() { let v = vec!(0); let _ = #[rustc_dummy] v[0]; let _ = (#[rustc_dummy] v)[0]; - let _ = #[rustc_dummy] 0..#[rustc_dummy] 0; - let _ = #[rustc_dummy] 0..; + let _ = (#[rustc_dummy] 0)..#[rustc_dummy] 0; + let _ = (#[rustc_dummy] 0)..; let _ = #[rustc_dummy] (0..0); let _ = #[rustc_dummy] (0..); let _ = #[rustc_dummy] (..0); diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 1204260a2f46f..fe0ceaf6b043d 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -3,8 +3,6 @@ // Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current // `rustc` version and the `since` property in feature stability gating is properly respected. -extern crate run_make_support; - use std::path::PathBuf; use run_make_support::{rustc, aux_build}; diff --git a/tests/run-make/a-b-a-linker-guard/rmake.rs b/tests/run-make/a-b-a-linker-guard/rmake.rs index ffc1b2000b90c..ee6d655bc760c 100644 --- a/tests/run-make/a-b-a-linker-guard/rmake.rs +++ b/tests/run-make/a-b-a-linker-guard/rmake.rs @@ -3,8 +3,6 @@ // Test that if we build `b` against a version of `a` that has one set of types, it will not run // with a dylib that has a different set of types. -extern crate run_make_support; - use run_make_support::{run, run_fail, rustc}; fn main() { diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs index 624a7fb22518d..13230206ca877 100644 --- a/tests/run-make/arguments-non-c-like-enum/rmake.rs +++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs @@ -1,8 +1,6 @@ //! Check that non-trivial `repr(C)` enum in Rust has valid C layout. //@ ignore-cross-compile -extern crate run_make_support; - use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib}; pub fn main() { diff --git a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs index de55de2a1ee20..6613698ae1dfe 100644 --- a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs +++ b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs @@ -5,8 +5,6 @@ // // Fixes: rust-lang/rust#123234 -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; fn main() { diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs index bb6513680818a..106f363eb8da1 100644 --- a/tests/run-make/artifact-incr-cache/rmake.rs +++ b/tests/run-make/artifact-incr-cache/rmake.rs @@ -7,8 +7,6 @@ // Also see discussion at // -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; fn main() { diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index 92d6895143c28..1784784845995 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -14,8 +14,6 @@ #![deny(warnings)] -extern crate run_make_support; - use run_make_support::object; use run_make_support::object::read::archive::ArchiveFile; use run_make_support::object::read::Object; @@ -63,7 +61,10 @@ fn main() { .env("RUSTC", rustc) .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes") .env("CARGO_TARGET_DIR", &target_dir) - .env("RUSTC_BOOTSTRAP", "1"); + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()); set_host_rpath(&mut cmd); let status = cmd.status().unwrap(); diff --git a/tests/run-make/core-no-fp-fmt-parse/rmake.rs b/tests/run-make/core-no-fp-fmt-parse/rmake.rs index 2748d4359c365..e3484888ca5a2 100644 --- a/tests/run-make/core-no-fp-fmt-parse/rmake.rs +++ b/tests/run-make/core-no-fp-fmt-parse/rmake.rs @@ -1,8 +1,6 @@ // This test checks that the core library of Rust can be compiled without enabling // support for formatting and parsing floating-point numbers. -extern crate run_make_support; - use run_make_support::rustc; use std::path::PathBuf; diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs index b534a99f8cfee..61f32762d8b71 100644 --- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -2,7 +2,6 @@ //! which requires extra `target-abi` metadata to be emitted. //@ needs-matching-clang //@ needs-llvm-components riscv -extern crate run_make_support; use run_make_support::{bin_name, clang, llvm_readobj, rustc, tmp_dir}; use std::{ diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs index f387626287e3f..f4ceabe126cbf 100644 --- a/tests/run-make/exit-code/rmake.rs +++ b/tests/run-make/exit-code/rmake.rs @@ -1,7 +1,5 @@ // Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations -extern crate run_make_support; - use run_make_support::{rustc, rustdoc, tmp_dir}; fn main() { diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index 40deabe15b73c..db25e9b033c13 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -2,7 +2,6 @@ #[cfg(unix)] extern crate libc; -extern crate run_make_support; use run_make_support::{aux_build, tmp_dir}; use std::fs; diff --git a/tests/run-make/no-input-file/Makefile b/tests/run-make/no-input-file/Makefile deleted file mode 100644 index a754573a52410..0000000000000 --- a/tests/run-make/no-input-file/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print crate-name 2>&1 | diff - no-input-file.stderr diff --git a/tests/run-make/no-input-file/rmake.rs b/tests/run-make/no-input-file/rmake.rs new file mode 100644 index 0000000000000..15e582311f09c --- /dev/null +++ b/tests/run-make/no-input-file/rmake.rs @@ -0,0 +1,7 @@ +use run_make_support::{diff, rustc}; + +fn main() { + let output = rustc().print("crate-name").run_fail_assert_exit_code(1); + + diff().expected_file("no-input-file.stderr").actual_text("output", output.stderr).run(); +} diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs index ba4aa1609b56c..a4843a52efd5b 100644 --- a/tests/run-make/non-unicode-env/rmake.rs +++ b/tests/run-make/non-unicode-env/rmake.rs @@ -1,5 +1,3 @@ -extern crate run_make_support; - use run_make_support::rustc; fn main() { diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index 129e424f27a41..40152e0411d39 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,5 +1,3 @@ -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; fn main() { diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile deleted file mode 100644 index 6b153e5b54edd..0000000000000 --- a/tests/run-make/print-cfg/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# needs-llvm-components: x86 arm - -include ../tools.mk - -all: default output_to_file - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) windows - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | $(CGREP) x86_64 - $(RUSTC) --target i686-pc-windows-msvc --print cfg | $(CGREP) msvc - $(RUSTC) --target i686-apple-darwin --print cfg | $(CGREP) macos - $(RUSTC) --target i686-unknown-linux-gnu --print cfg | $(CGREP) gnu - $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) target_abi= - $(RUSTC) --target arm-unknown-linux-gnueabihf --print cfg | $(CGREP) eabihf - -output_to_file: - # Backend-independent, printed by rustc_driver_impl/src/lib.rs - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt - $(CGREP) windows < $(TMPDIR)/cfg.txt - - # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs - $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt - $(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt - - # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs - $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt - $(CGREP) reference-types < $(TMPDIR)/target-features.txt - - # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp - $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt - $(CGREP) generic < $(TMPDIR)/target-cpus.txt - -ifdef IS_WINDOWS -default: - $(RUSTC) --print cfg | $(CGREP) windows -else -default: - $(RUSTC) --print cfg | $(CGREP) unix -endif diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs new file mode 100644 index 0000000000000..6e72c16f1f9a9 --- /dev/null +++ b/tests/run-make/print-cfg/rmake.rs @@ -0,0 +1,104 @@ +//! This checks the output of `--print=cfg` +//! +//! Specifically it checks that output is correctly formatted +//! (ie. no duplicated cfgs, values are between "", names are not). +//! +//! It also checks that some targets have the correct set cfgs. + +use std::collections::HashSet; +use std::ffi::OsString; +use std::io::BufRead; +use std::iter::FromIterator; + +use run_make_support::{rustc, tmp_dir}; + +struct PrintCfg { + target: &'static str, + includes: &'static [&'static str], + disallow: &'static [&'static str], +} + +fn main() { + check(PrintCfg { + target: "x86_64-pc-windows-gnu", + includes: &["windows", "target_arch=\"x86_64\""], + disallow: &["unix"], + }); + check(PrintCfg { + target: "i686-pc-windows-msvc", + includes: &["windows", "target_env=\"msvc\""], + disallow: &["unix"], + }); + check(PrintCfg { + target: "i686-apple-darwin", + includes: &["unix", "target_os=\"macos\"", "target_vendor=\"apple\""], + disallow: &["windows"], + }); + check(PrintCfg { + target: "i686-unknown-linux-gnu", + includes: &["unix", "target_env=\"gnu\""], + disallow: &["windows"], + }); + check(PrintCfg { + target: "arm-unknown-linux-gnueabihf", + includes: &["unix", "target_abi=\"eabihf\""], + disallow: &["windows"], + }); +} + +fn check(PrintCfg { target, includes, disallow }: PrintCfg) { + fn check_(output: &str, includes: &[&str], disallow: &[&str]) { + let mut found = HashSet::::new(); + let mut recorded = HashSet::::new(); + + for l in output.lines() { + assert!(l == l.trim()); + if let Some((left, right)) = l.split_once('=') { + assert!(right.starts_with("\"")); + assert!(right.ends_with("\"")); + assert!(!left.contains("\"")); + } else { + assert!(!l.contains("\"")); + } + + assert!(recorded.insert(l.to_string()), "duplicated: {}", &l); + assert!(!disallow.contains(&l), "found disallowed: {}", &l); + if includes.contains(&l) { + assert!(found.insert(l.to_string()), "duplicated (includes): {}", &l); + } + } + + let should_found = HashSet::::from_iter(includes.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_found.difference(&found).collect(); + + assert!( + diff.is_empty(), + "expected: {:?}, found: {:?} (~ {:?})", + &should_found, + &found, + &diff + ); + } + + // --print=cfg + { + let output = rustc().target(target).print("cfg").run(); + + let stdout = String::from_utf8(output.stdout).unwrap(); + + check_(&stdout, includes, disallow); + } + + // --print=cfg=PATH + { + let tmp_path = tmp_dir().join(format!("{target}.cfg")); + let mut print_arg = OsString::from("--print=cfg="); + print_arg.push(tmp_path.as_os_str()); + + let output = rustc().target(target).arg(print_arg).run(); + + let output = std::fs::read_to_string(&tmp_path).unwrap(); + + check_(&output, includes, disallow); + } +} diff --git a/tests/run-make/print-native-static-libs/Makefile b/tests/run-make/print-native-static-libs/Makefile deleted file mode 100644 index a16c8b0f2a405..0000000000000 --- a/tests/run-make/print-native-static-libs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile -# ignore-wasm - -all: - $(RUSTC) --crate-type rlib -lbar_cli bar.rs - $(RUSTC) foo.rs -lfoo_cli -lfoo_cli --crate-type staticlib --print native-static-libs 2>&1 \ - | grep 'note: native-static-libs: ' \ - | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt - - cat $(TMPDIR)/libs.txt | grep -F "glib-2.0" # in bar.rs - cat $(TMPDIR)/libs.txt | grep -F "systemd" # in foo.rs - cat $(TMPDIR)/libs.txt | grep -F "bar_cli" - cat $(TMPDIR)/libs.txt | grep -F "foo_cli" - - # make sure that foo_cli and glib-2.0 are not consecutively present - cat $(TMPDIR)/libs.txt | grep -Fv "foo_cli -lfoo_cli" - cat $(TMPDIR)/libs.txt | grep -Fv "glib-2.0 -lglib-2.0" diff --git a/tests/run-make/print-native-static-libs/rmake.rs b/tests/run-make/print-native-static-libs/rmake.rs new file mode 100644 index 0000000000000..5249920cc60e5 --- /dev/null +++ b/tests/run-make/print-native-static-libs/rmake.rs @@ -0,0 +1,74 @@ +//! This checks the output of `--print=native-static-libs` +//! +//! Specifically, this test makes sure that one and only one +//! note is emitted with the text "native-static-libs:" as prefix +//! that the note contains the link args given in the source code +//! and cli of the current crate and downstream crates. +//! +//! It also checks that there aren't any duplicated consecutive +//! args, as they are useless and suboptimal for debugability. +//! See https://github.com/rust-lang/rust/issues/113209. + +//@ ignore-cross-compile +//@ ignore-wasm + +use std::io::BufRead; + +use run_make_support::{rustc, is_msvc}; + +fn main() { + // build supporting crate + rustc() + .input("bar.rs") + .crate_type("rlib") + .arg("-lbar_cli") + .run(); + + // build main crate as staticlib + let output = rustc() + .input("foo.rs") + .crate_type("staticlib") + .arg("-lfoo_cli") + .arg("-lfoo_cli") // 2nd time + .print("native-static-libs") + .run(); + + let mut found_note = false; + for l in output.stderr.lines() { + let l = l.expect("utf-8 string"); + + let Some(args) = l.strip_prefix("note: native-static-libs:") else { continue; }; + assert!(!found_note); + found_note = true; + + let args: Vec<&str> = args.trim().split_ascii_whitespace().collect(); + + macro_rules! assert_contains_lib { + ($lib:literal in $args:ident) => {{ + let lib = format!( + "{}{}{}", + if !is_msvc() { "-l" } else { "" }, + $lib, + if !is_msvc() { "" } else { ".lib" }, + ); + let found = $args.contains(&&*lib); + assert!(found, "unable to find lib `{}` in those linker args: {:?}", lib, $args); + }} + } + + assert_contains_lib!("glib-2.0" in args); // in bar.rs + assert_contains_lib!("systemd" in args); // in foo.rs + assert_contains_lib!("bar_cli" in args); + assert_contains_lib!("foo_cli" in args); + + // make sure that no args are consecutively present + let dedup_args: Vec<&str> = { + let mut args = args.clone(); + args.dedup(); + args + }; + assert_eq!(args, dedup_args); + } + + assert!(found_note); +} diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs new file mode 100644 index 0000000000000..f710d0dc3c9b5 --- /dev/null +++ b/tests/run-make/print-to-output/rmake.rs @@ -0,0 +1,66 @@ +//! This checks the output of some `--print` options when +//! output to a file (instead of stdout) + +use std::ffi::OsString; + +use run_make_support::{rustc, target, tmp_dir}; + +struct Option<'a> { + target: &'a str, + option: &'static str, + includes: &'static [&'static str], +} + +fn main() { + // Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs + check(Option { + target: &target(), + option: "relocation-models", + includes: &["dynamic-no-pic"], + }); + + // Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs + check(Option { + target: "wasm32-unknown-unknown", + option: "target-features", + includes: &["reference-types"], + }); + + // Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp + check(Option { + target: "wasm32-unknown-unknown", + option: "target-cpus", + includes: &["generic"], + }); +} + +fn check(args: Option) { + fn check_(output: &str, includes: &[&str]) { + for i in includes { + assert!(output.contains(i), "output doesn't contains: {}", i); + } + } + + // --print={option} + let stdout = { + let output = rustc().target(args.target).print(args.option).run(); + + String::from_utf8(output.stdout).unwrap() + }; + + // --print={option}=PATH + let output = { + let tmp_path = tmp_dir().join(format!("{}.txt", args.option)); + let mut print_arg = OsString::from(format!("--print={}=", args.option)); + print_arg.push(tmp_path.as_os_str()); + + let _output = rustc().target(args.target).arg(print_arg).run(); + + std::fs::read_to_string(&tmp_path).unwrap() + }; + + check_(&stdout, args.includes); + check_(&output, args.includes); + + assert_eq!(&stdout, &output); +} diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile index a8f97edd68936..2524f8500e154 100644 --- a/tests/run-make/raw-dylib-cross-compilation/Makefile +++ b/tests/run-make/raw-dylib-cross-compilation/Makefile @@ -1,8 +1,6 @@ # Tests that raw-dylib cross compilation works correctly -# only-gnu -# needs-i686-dlltool -# needs-x86_64-dlltool +# needs-dlltool # i686 dlltool.exe can't product x64 binaries. # ignore-i686-pc-windows-gnu diff --git a/tests/run-make/repr128-dwarf/Makefile b/tests/run-make/repr128-dwarf/Makefile deleted file mode 100644 index 3f933042724a3..0000000000000 --- a/tests/run-make/repr128-dwarf/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# ignore-windows -# This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit -# enums. - -include ../tools.mk - -all: - $(RUSTC) -Cdebuginfo=2 lib.rs -o $(TMPDIR)/repr128.rlib - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128A $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128B $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128C $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n U128D $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128A $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128B $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128C $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 )" - "$(LLVM_BIN_DIR)"/llvm-dwarfdump -n I128D $(TMPDIR)/repr128.rlib | $(CGREP) "DW_AT_const_value (<0x10> ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7f )" diff --git a/tests/run-make/repr128-dwarf/lib.rs b/tests/run-make/repr128-dwarf/main.rs similarity index 89% rename from tests/run-make/repr128-dwarf/lib.rs rename to tests/run-make/repr128-dwarf/main.rs index 63675441d4bab..57923a8386db9 100644 --- a/tests/run-make/repr128-dwarf/lib.rs +++ b/tests/run-make/repr128-dwarf/main.rs @@ -1,4 +1,3 @@ -#![crate_type = "lib"] #![feature(repr128)] // Use .to_le() to ensure that the bytes are in the same order on both little- and big-endian @@ -21,3 +20,7 @@ pub enum I128Enum { } pub fn f(_: U128Enum, _: I128Enum) {} + +fn main() { + f(U128Enum::U128A, I128Enum::I128A); +} diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs new file mode 100644 index 0000000000000..d734b2add79a2 --- /dev/null +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -0,0 +1,73 @@ +//@ ignore-windows +// This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit enums. + +use gimli::{AttributeValue, Dwarf, EndianRcSlice, Reader, RunTimeEndian}; +use object::{Object, ObjectSection}; +use run_make_support::{gimli, object, rustc, tmp_dir}; +use std::borrow::Cow; +use std::collections::HashMap; +use std::rc::Rc; + +fn main() { + let output = tmp_dir().join("repr128"); + rustc().input("main.rs").arg("-o").arg(&output).arg("-Cdebuginfo=2").run(); + // Mach-O uses packed debug info + let dsym_location = output + .with_extension("dSYM") + .join("Contents") + .join("Resources") + .join("DWARF") + .join("repr128"); + let output = + std::fs::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output }) + .unwrap(); + let obj = object::File::parse(output.as_slice()).unwrap(); + let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big }; + let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> { + let data = obj.section_by_name(section.name()).map(|s| s.uncompressed_data().unwrap()); + Ok(EndianRcSlice::new(Rc::from(data.unwrap_or_default().as_ref()), endian)) + }) + .unwrap(); + let mut iter = dwarf.units(); + let mut still_to_find = HashMap::from([ + ("U128A", 0_u128), + ("U128B", 1_u128), + ("U128C", u64::MAX as u128 + 1), + ("U128D", u128::MAX), + ("I128A", 0_i128 as u128), + ("I128B", (-1_i128) as u128), + ("I128C", i128::MIN as u128), + ("I128D", i128::MAX as u128), + ]); + while let Some(header) = iter.next().unwrap() { + let unit = dwarf.unit(header).unwrap(); + let mut cursor = unit.entries(); + while let Some((_, entry)) = cursor.next_dfs().unwrap() { + if entry.tag() == gimli::constants::DW_TAG_enumerator { + let name = dwarf + .attr_string( + &unit, + entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(), + ) + .unwrap(); + let name = name.to_string().unwrap(); + if let Some(expected) = still_to_find.remove(name.as_ref()) { + match entry.attr(gimli::constants::DW_AT_const_value).unwrap().unwrap().value() + { + AttributeValue::Block(value) => { + assert_eq!( + value.to_slice().unwrap(), + expected.to_le_bytes().as_slice(), + "{name}" + ); + } + value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"), + } + } + } + } + } + if !still_to_find.is_empty() { + panic!("Didn't find debug entries for {still_to_find:?}"); + } +} diff --git a/tests/run-make/rust-lld-custom-target/rmake.rs b/tests/run-make/rust-lld-custom-target/rmake.rs index b5341725e36ea..9bdb69f47d8ec 100644 --- a/tests/run-make/rust-lld-custom-target/rmake.rs +++ b/tests/run-make/rust-lld-custom-target/rmake.rs @@ -8,8 +8,6 @@ //@ needs-rust-lld //@ only-x86_64-unknown-linux-gnu -extern crate run_make_support; - use run_make_support::regex::Regex; use run_make_support::rustc; use std::process::Output; diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs index acb6d74aaa8be..feeb82e709e16 100644 --- a/tests/run-make/rust-lld/rmake.rs +++ b/tests/run-make/rust-lld/rmake.rs @@ -5,8 +5,6 @@ //@ ignore-msvc //@ ignore-s390x lld does not yet support s390x as target -extern crate run_make_support; - use run_make_support::regex::Regex; use run_make_support::rustc; use std::process::Output; diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index c8edfb6370e50..66f3f7cf131c7 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,5 +1,3 @@ -extern crate run_make_support; - use run_make_support::{rustdoc, tmp_dir}; use std::path::Path; use std::{fs, iter}; diff --git a/tests/run-make/valid-print-requests/Makefile b/tests/run-make/valid-print-requests/Makefile deleted file mode 100644 index 99430e98d1c2d..0000000000000 --- a/tests/run-make/valid-print-requests/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print uwu 2>&1 | diff - valid-print-requests.stderr diff --git a/tests/run-make/valid-print-requests/valid-print-requests.stderr b/tests/run-make/valid-print-requests/valid-print-requests.stderr deleted file mode 100644 index 22bb102f9c989..0000000000000 --- a/tests/run-make/valid-print-requests/valid-print-requests.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: unknown print request `uwu`. Valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` - diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs index d83332f6e0341..a2dcafbbe0f14 100644 --- a/tests/run-make/wasm-abi/rmake.rs +++ b/tests/run-make/wasm-abi/rmake.rs @@ -1,8 +1,6 @@ //@ only-wasm32-wasip1 //@ needs-wasmtime -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; use std::path::Path; use std::process::Command; diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index 825fcf71514c6..0303ca05ca631 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,5 +1,4 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::HashMap; diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index 634683adc220d..24570d8baf5a6 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,5 +1,4 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index 400d6db5651c1..50c99d027d5ac 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,7 +1,5 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; - use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; use std::path::Path; diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index 1b814e9ccce30..333d0df4653fa 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,7 +1,5 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; - use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; use wasmparser::TypeRef::Func; diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index bffa311d93a11..373b966401cea 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,8 +1,6 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; fn main() { diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 8f716061d28ba..458c7bfccb74a 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,7 +1,5 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::HashMap; diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 5efbfee8d3834..9fac0c0c215d0 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,8 +1,6 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -extern crate run_make_support; - use run_make_support::{rustc, tmp_dir}; fn main() { diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 88bd16a404c70..521d2c31ee61c 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,5 +1,4 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::{HashMap, HashSet}; diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index c9207f70ae5f2..1b020b67a3852 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,5 +1,4 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; use run_make_support::{rustc, tmp_dir, wasmparser}; use std::path::Path; diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index 4d41dc7c0aa8f..a653ab61b2c00 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,5 +1,4 @@ //@ only-wasm32-wasip1 -extern crate run_make_support; use run_make_support::{rustc, tmp_dir, wasmparser}; use std::path::Path; diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 34fafe9a14120..6ee810c5768c2 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -2,47 +2,70 @@ include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" show-text: true -// We start with a wide screen. -set-window-size: (1100, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 677}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 955}, -) -// The tooltip should be below the `i` -// Also, clicking the tooltip should bring its text into the DOM -assert-count: ("//*[@class='tooltip popover']", 0) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) -compare-elements-position-near: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - {"y": 30} + +define-function: ( + "check-notable-tooltip-position", + [x, i_x], + block { + // Checking they have the same y position. + compare-elements-position: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + ["y"], + ) + // Checking they don't have the same x position. + compare-elements-position-false: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + ["x"], + ) + // The `i` should be *after* the type. + assert-position: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + {"x": |x|}, + ) + assert-position: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + {"x": |i_x|}, + ) + }, ) -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - ["x"] + +define-function: ( + "check-notable-tooltip-position-complete", + [x, i_x, popover_x], + block { + call-function: ("check-notable-tooltip-position", {"x": |x|, "i_x": |i_x|}) + assert-count: ("//*[@class='tooltip popover']", 0) + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + assert-count: ("//*[@class='tooltip popover']", 1) + compare-elements-position-near: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + "//*[@class='tooltip popover']", + {"y": 30} + ) + compare-elements-position-false: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + "//*[@class='tooltip popover']", + ["x"] + ) + assert-position: ( + "//*[@class='tooltip popover']", + {"x": |popover_x|} + ) + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + move-cursor-to: "//h1" + assert-count: ("//*[@class='tooltip popover']", 0) + }, ) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -move-cursor-to: "//h1" -assert-count: ("//*[@class='tooltip popover']", 0) + +// We start with a wide screen. +set-window-size: (1100, 600) +call-function: ("check-notable-tooltip-position-complete", { + "x": 677, + "i_x": 955, + "popover_x": 463, +}) // Now only the `i` should be on the next line. set-window-size: (1055, 600) @@ -54,71 +77,18 @@ compare-elements-position-false: ( // Now both the `i` and the struct name should be on the next line. set-window-size: (980, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 245}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 523}, -) +call-function: ("check-notable-tooltip-position", { + "x": 245, + "i_x": 523, +}) // Checking on mobile now. set-window-size: (650, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 15}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 293}, -) -// The tooltip should STILL be below `i` -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) -compare-elements-position-near: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - {"y": 30} -) -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - ["x"] -) -assert-position: ( - "//*[@class='tooltip popover']", - {"x": 0} -) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -move-cursor-to: "//h1" -assert-count: ("//*[@class='tooltip popover']", 0) +call-function: ("check-notable-tooltip-position-complete", { + "x": 15, + "i_x": 293, + "popover_x": 0, +}) // Now check the colors. define-function: ( @@ -236,31 +206,31 @@ press-key: "Tab" assert-count: ("//*[@class='tooltip popover']", 0) assert: "#method\.create_an_iterator_from_read .tooltip:focus" +define-function: ( + "setup-popup", + [], + block { + store-window-property: {"scrollY": scroll} + click: "#method\.create_an_iterator_from_read .fn" + // We ensure that the scroll position changed. + assert-window-property-false: {"scrollY": |scroll|} + // Store the new position. + store-window-property: {"scrollY": scroll} + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + wait-for: "//*[@class='tooltip popover']" + click: "#settings-menu a" + } +) + // Now we check that the focus isn't given back to the wrong item when opening // another popover. -store-window-property: {"scrollY": scroll} -click: "#method\.create_an_iterator_from_read .fn" -// We ensure that the scroll position changed. -assert-window-property-false: {"scrollY": |scroll|} -// Store the new position. -store-window-property: {"scrollY": scroll} -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -wait-for: "//*[@class='tooltip popover']" -click: "#settings-menu a" +call-function: ("setup-popup", {}) click: ".search-input" // We ensure we didn't come back to the previous focused item. assert-window-property-false: {"scrollY": |scroll|} // Same but with Escape handling. -store-window-property: {"scrollY": scroll} -click: "#method\.create_an_iterator_from_read .fn" -// We ensure that the scroll position changed. -assert-window-property-false: {"scrollY": |scroll|} -// Store the new position. -store-window-property: {"scrollY": scroll} -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -wait-for: "//*[@class='tooltip popover']" -click: "#settings-menu a" +call-function: ("setup-popup", {}) press-key: "Escape" // We ensure we didn't come back to the previous focused item. assert-window-property-false: {"scrollY": |scroll|} diff --git a/tests/rustdoc-ui/doctest/non_local_defs.rs b/tests/rustdoc-ui/doctest/non_local_defs.rs new file mode 100644 index 0000000000000..aa166c343b2b0 --- /dev/null +++ b/tests/rustdoc-ui/doctest/non_local_defs.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ compile-flags:--test --test-args --test-threads=1 --nocapture -Zunstable-options +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +//! ``` +//! #[macro_export] +//! macro_rules! a_macro { () => {} } +//! ``` diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stderr b/tests/rustdoc-ui/doctest/non_local_defs.stderr new file mode 100644 index 0000000000000..39a25de1aae79 --- /dev/null +++ b/tests/rustdoc-ui/doctest/non_local_defs.stderr @@ -0,0 +1,14 @@ +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/non_local_defs.rs:9:1 + | +LL | macro_rules! a_macro { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() { ... }` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `#[warn(non_local_definitions)]` on by default + +warning: 1 warning emitted + diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stdout b/tests/rustdoc-ui/doctest/non_local_defs.stdout new file mode 100644 index 0000000000000..bee195fcdd772 --- /dev/null +++ b/tests/rustdoc-ui/doctest/non_local_defs.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/non_local_defs.rs - (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/invalid_associated_const.stderr b/tests/rustdoc-ui/invalid_associated_const.stderr index 1eb6d2714e31b..5eaddc2b8c984 100644 --- a/tests/rustdoc-ui/invalid_associated_const.stderr +++ b/tests/rustdoc-ui/invalid_associated_const.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/invalid_associated_const.rs:4:17 @@ -11,6 +16,10 @@ LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/rustdoc-ui/issue-102467.stderr b/tests/rustdoc-ui/issue-102467.stderr index f54a50a4e1952..119ca949e999a 100644 --- a/tests/rustdoc-ui/issue-102467.stderr +++ b/tests/rustdoc-ui/issue-102467.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-102467.rs:7:17 @@ -11,6 +16,10 @@ LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/rustdoc/resolve-ice-124363.rs b/tests/rustdoc/resolve-ice-124363.rs new file mode 100644 index 0000000000000..111916cc59050 --- /dev/null +++ b/tests/rustdoc/resolve-ice-124363.rs @@ -0,0 +1,7 @@ +/** +*/ +pub mod A { + #![doc = "{ + Foo { }, + }"] +} diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 1d7417be58cc3..380b2b6c431d5 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -59,7 +59,7 @@ impl Subdiagnostic for UntranslatableInAddtoDiag { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages @@ -72,7 +72,7 @@ impl Subdiagnostic for TranslatableInAddtoDiag { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, - f: F, + f: &F, ) { diag.note(crate::fluent_generated::no_crate_note); } diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 163af7ff0e214..659ae54f7a3be 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -827,3 +827,13 @@ struct PrimarySpanOnVec { //~| NOTE there must be exactly one primary span sub: Vec, } + +#[derive(Subdiagnostic)] +struct NestedParent { + #[subdiagnostic] + single_sub: A, + #[subdiagnostic] + option_sub: Option, + #[subdiagnostic] + vec_sub: Vec, +} diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index e7d852a27df0e..6345ee24f7893 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -137,9 +137,9 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" - #![feature(panic_internals)] + fn panic_str(msg: &str) {{ panic!("{{}}", msg); }} pub fn dummy() {{ - core::panicking::panic_str("oops"); + panic_str("oops"); }} "# )?; diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 3ee4542810c65..373d1cce1d73d 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -64,7 +64,6 @@ [csky] needs-llvm-components: csky */ #![feature(rustc_attrs, unsized_fn_params, transparent_unions)] -#![cfg_attr(host, feature(generic_nonzero))] #![cfg_attr(not(host), feature(no_core, lang_items), no_std, no_core)] #![allow(unused, improper_ctypes_definitions, internal_features)] diff --git a/tests/ui/asm/x86_64/target-feature-attr.rs b/tests/ui/asm/x86_64/target-feature-attr.rs index 820be132ef794..6bb277ac16598 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.rs +++ b/tests/ui/asm/x86_64/target-feature-attr.rs @@ -1,4 +1,6 @@ //@ only-x86_64 +// Set the base cpu explicitly, in case the default has been changed. +//@ compile-flags: -C target-cpu=x86-64 #![feature(avx512_target_feature)] diff --git a/tests/ui/asm/x86_64/target-feature-attr.stderr b/tests/ui/asm/x86_64/target-feature-attr.stderr index c852726ee7ff8..0cd571ac8cce8 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.stderr +++ b/tests/ui/asm/x86_64/target-feature-attr.stderr @@ -1,23 +1,23 @@ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:40 + --> $DIR/target-feature-attr.rs:20:40 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:55 + --> $DIR/target-feature-attr.rs:20:55 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:70 + --> $DIR/target-feature-attr.rs:20:70 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^^^^^^ error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f - --> $DIR/target-feature-attr.rs:33:23 + --> $DIR/target-feature-attr.rs:35:23 | LL | asm!("/* {0} */", in(kreg) x); | ^^^^^^^^^^ diff --git a/tests/ui/assoc-lang-items.stderr b/tests/ui/assoc-lang-items.stderr index 040792fb1cd5f..59aec8e3fdc6e 100644 --- a/tests/ui/assoc-lang-items.stderr +++ b/tests/ui/assoc-lang-items.stderr @@ -1,26 +1,26 @@ -error[E0522]: definition of an unknown language item: `dummy_lang_item_1` +error[E0522]: definition of an unknown lang item: `dummy_lang_item_1` --> $DIR/assoc-lang-items.rs:4:5 | LL | #[lang = "dummy_lang_item_1"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_1` -error[E0522]: definition of an unknown language item: `dummy_lang_item_2` +error[E0522]: definition of an unknown lang item: `dummy_lang_item_2` --> $DIR/assoc-lang-items.rs:7:5 | LL | #[lang = "dummy_lang_item_2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_2` -error[E0522]: definition of an unknown language item: `dummy_lang_item_3` +error[E0522]: definition of an unknown lang item: `dummy_lang_item_3` --> $DIR/assoc-lang-items.rs:10:5 | LL | #[lang = "dummy_lang_item_3"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_3` -error[E0522]: definition of an unknown language item: `dummy_lang_item_4` +error[E0522]: definition of an unknown lang item: `dummy_lang_item_4` --> $DIR/assoc-lang-items.rs:17:5 | LL | #[lang = "dummy_lang_item_4"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_4` error: aborting due to 4 previous errors diff --git a/tests/ui/associated-consts/issue-102335-const.stderr b/tests/ui/associated-consts/issue-102335-const.stderr index 2a70425a3cc87..905d7c75c2000 100644 --- a/tests/ui/associated-consts/issue-102335-const.stderr +++ b/tests/ui/associated-consts/issue-102335-const.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-102335-const.rs:4:17 @@ -11,6 +16,10 @@ LL | type A: S = 34>; | ^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = 34>; + | ~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/associated-type-bounds/issue-102335-ty.rs b/tests/ui/associated-type-bounds/issue-102335-ty.rs index 5fd8b71e679b2..b2df68b18ae4d 100644 --- a/tests/ui/associated-type-bounds/issue-102335-ty.rs +++ b/tests/ui/associated-type-bounds/issue-102335-ty.rs @@ -1,5 +1,11 @@ trait T { - type A: S = ()>; + type A: S = ()>; // Just one erroneous equality constraint + //~^ ERROR associated type bindings are not allowed here + //~| ERROR associated type bindings are not allowed here +} + +trait T2 { + type A: S = ()>; // More than one erroneous equality constraints //~^ ERROR associated type bindings are not allowed here //~| ERROR associated type bindings are not allowed here } diff --git a/tests/ui/associated-type-bounds/issue-102335-ty.stderr b/tests/ui/associated-type-bounds/issue-102335-ty.stderr index 3bd7566ad1e0a..cf30b0a4f6cad 100644 --- a/tests/ui/associated-type-bounds/issue-102335-ty.stderr +++ b/tests/ui/associated-type-bounds/issue-102335-ty.stderr @@ -1,17 +1,49 @@ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-102335-ty.rs:2:17 | -LL | type A: S = ()>; +LL | type A: S = ()>; // Just one erroneous equality constraint | ^^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = ()>; // Just one erroneous equality constraint + | ~~~~~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-102335-ty.rs:2:17 | -LL | type A: S = ()>; +LL | type A: S = ()>; // Just one erroneous equality constraint + | ^^^^^^^^^ associated type not allowed here + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = ()>; // Just one erroneous equality constraint + | ~~~~~~~~~~~ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-ty.rs:8:17 + | +LL | type A: S = ()>; // More than one erroneous equality constraints + | ^^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = ()>; // More than one erroneous equality constraints + | ~~~~~~~~~~ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-ty.rs:8:17 + | +LL | type A: S = ()>; // More than one erroneous equality constraints | ^^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = ()>; // More than one erroneous equality constraints + | ~~~~~~~~~~ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0229`. diff --git a/tests/ui/associated-types/associated-types-eq-2.rs b/tests/ui/associated-types/associated-types-eq-2.rs index 18e38d4466702..d71697e9a8325 100644 --- a/tests/ui/associated-types/associated-types-eq-2.rs +++ b/tests/ui/associated-types/associated-types-eq-2.rs @@ -1,19 +1,125 @@ // Test equality constraints on associated types. Check we get an error when an -// equality constraint is used in a qualified path. +// equality constraint is used in an invalid context -pub trait Foo { +struct Bar; +struct Qux; + +// Tests for a a non generic trait +pub trait Tr1 { type A; - fn boo(&self) -> ::A; + fn boo(&self) -> ::A; } -struct Bar; - -impl Foo for isize { +impl Tr1 for isize { type A = usize; fn boo(&self) -> usize { 42 } } -fn baz(x: &>::A) {} +// Test for when the assoc type is +// specified as an equality constraint +impl Tr1 for usize { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR not all trait items implemented, missing: `A` + fn boo(&self) -> usize { 42 } +} + +// Test for a wronngly used equality constraint in a func arg +fn baz(_x: &>::A) {} +//~^ ERROR associated type bindings are not allowed here + + + +// Tests for a generic trait +trait Tr2 { +} + +// Test for when wrongly specifed equality constraint's ident +// matches some generic param's ident +// (Note: E0229 is emitted only for the first erroneous equality +// constraint (T2) not for any subequent ones (e.g. T3)) +impl Tr2 for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied +} + +// Test for when equality constraint's ident matches a +// generic param's ident but has different case +impl Tr2 for Qux { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied +} + +// Test for when equality constraint's ident +// matches none of the generic param idents +impl Tr2 for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied +} + +// Test for when the term in equality constraint is itself generic +struct GenericTerm { _t: T } +impl Tr2> for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR trait takes 3 generic arguments but 2 generic arguments were supplied +} + + + +// Tests for a trait with a const param +trait Tr3 { +} + +// Test for when equality constraint's ident +// matches the const param's ident +// (Deliberately spread over multiple lines to test that +// our suggestion spans are kosher in the face of such formatting) +impl Tr3 for Bar { +} + +// Test for when equality constraint's ident +// matches the const param's ident but has a different case +impl Tr3 for Qux { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR associated const equality is incomplete +//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied +} + +// Test for when equality constraint's ident +// matches the const param ident but the constraint is a type arg +impl Tr3 for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied +} + +// Test for when equality constraint's ident +// matches a type param ident but the constraint is a const arg +impl Tr3<42, T2 = 42, T3 = usize> for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR associated const equality is incomplete +//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied +} + +// Test for when equality constraint's ident +// matches none of the param idents +impl Tr3 for Bar { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR associated const equality is incomplete +//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied +} + + + +// Test for the case when lifetimes are present +struct St<'a, T> { v: &'a T } + +impl<'a, T> St<'a , T = Qux> { +//~^ ERROR associated type bindings are not allowed here +//~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied +} + pub fn main() {} diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 447b8413ee294..b68c82f590c14 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -1,9 +1,365 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/associated-types-eq-2.rs:76:10 + | +LL | impl Tr3 for Bar { + | |____^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: associated const equality is incomplete + --> $DIR/associated-types-eq-2.rs:85:10 + | +LL | impl Tr3 for Qux { + | ^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: associated const equality is incomplete + --> $DIR/associated-types-eq-2.rs:100:14 + | +LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { + | ^^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: associated const equality is incomplete + --> $DIR/associated-types-eq-2.rs:108:10 + | +LL | impl Tr3 for Bar { + | ^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0229]: associated type bindings are not allowed here - --> $DIR/associated-types-eq-2.rs:16:30 + --> $DIR/associated-types-eq-2.rs:20:10 + | +LL | impl Tr1 for usize { + | ^^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr1 for usize { + | ~~~~~~~~~~~ + +error[E0046]: not all trait items implemented, missing: `A` + --> $DIR/associated-types-eq-2.rs:20:1 + | +LL | type A; + | ------ `A` from trait +... +LL | impl Tr1 for usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `A` in implementation + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:27:31 + | +LL | fn baz(_x: &>::A) {} + | ^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | fn baz(_x: &>::A) {} + | ~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/associated-types-eq-2.rs:40:6 + | +LL | impl Tr2 for Bar { + | ^^^ --- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:33:7 + | +LL | trait Tr2 { + | ^^^ -- -- -- +help: add missing generic arguments + | +LL | impl Tr2 for Bar { + | ++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:40:15 + | +LL | impl Tr2 for Bar { + | ^^^^^^^^ associated type not allowed here + | +help: to use `Qux` as a generic argument specify it directly + | +LL | impl Tr2 for Bar { + | ~~~ + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/associated-types-eq-2.rs:47:6 + | +LL | impl Tr2 for Qux { + | ^^^ --- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:33:7 + | +LL | trait Tr2 { + | ^^^ -- -- -- +help: add missing generic arguments + | +LL | impl Tr2 for Qux { + | ++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:47:15 + | +LL | impl Tr2 for Qux { + | ^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr2 for Qux { + | ~~~~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/associated-types-eq-2.rs:54:6 + | +LL | impl Tr2 for Bar { + | ^^^ --- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:33:7 + | +LL | trait Tr2 { + | ^^^ -- -- -- +help: add missing generic arguments + | +LL | impl Tr2 for Bar { + | ++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:54:15 + | +LL | impl Tr2 for Bar { + | ^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr2 for Bar { + | ~~~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 2 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:61:6 + | +LL | impl Tr2> for Bar { + | ^^^ --- --- supplied 2 generic arguments + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:33:7 + | +LL | trait Tr2 { + | ^^^ -- -- -- +help: add missing generic argument + | +LL | impl Tr2> for Bar { + | ++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:61:20 + | +LL | impl Tr2> for Bar { + | ^^^^^^^^^^^^^^^^^^^^^ associated type not allowed here + | +help: to use `GenericTerm` as a generic argument specify it directly + | +LL | impl Tr2> for Bar { + | ~~~~~~~~~~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:76:6 + | +LL | impl Tr3 $DIR/associated-types-eq-2.rs:69:7 + | +LL | trait Tr3 { + | ^^^ ------------ -- -- +help: add missing generic arguments + | +LL | impl Tr3 $DIR/associated-types-eq-2.rs:76:10 + | +LL | impl Tr3 for Bar { + | |____^ associated type not allowed here + | +help: to use `42` as a generic argument specify it directly + | +LL | impl Tr3<42, T2 = Qux, T3 = usize> for Bar { + | ~~ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:85:6 + | +LL | impl Tr3 for Qux { + | ^^^ expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:69:7 + | +LL | trait Tr3 { + | ^^^ ------------ -- -- +help: add missing generic arguments + | +LL | impl Tr3 for Qux { + | ++++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:85:10 + | +LL | impl Tr3 for Qux { + | ^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr3 for Qux { + | ~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:93:6 + | +LL | impl Tr3 for Bar { + | ^^^ expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:69:7 + | +LL | trait Tr3 { + | ^^^ ------------ -- -- +help: add missing generic arguments + | +LL | impl Tr3 for Bar { + | ++++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:93:10 + | +LL | impl Tr3 for Bar { + | ^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr3 for Bar { + | ~~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/associated-types-eq-2.rs:100:6 + | +LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { + | ^^^ -- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:69:7 + | +LL | trait Tr3 { + | ^^^ ------------ -- -- +help: add missing generic arguments + | +LL | impl Tr3<42, T2, T3, T2 = 42, T3 = usize> for Bar { + | ++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:100:14 + | +LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { + | ^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { + | ~~~~~~~~~ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:108:6 + | +LL | impl Tr3 for Bar { + | ^^^ expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` + --> $DIR/associated-types-eq-2.rs:69:7 + | +LL | trait Tr3 { + | ^^^ ------------ -- -- +help: add missing generic arguments + | +LL | impl Tr3 for Bar { + | ++++++++++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:108:10 + | +LL | impl Tr3 for Bar { + | ^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | impl Tr3 for Bar { + | ~~~~~~~ + +error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/associated-types-eq-2.rs:119:13 + | +LL | impl<'a, T> St<'a , T = Qux> { + | ^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/associated-types-eq-2.rs:117:8 + | +LL | struct St<'a, T> { v: &'a T } + | ^^ - +help: add missing generic argument + | +LL | impl<'a, T> St<'a, T , T = Qux> { + | +++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/associated-types-eq-2.rs:119:21 + | +LL | impl<'a, T> St<'a , T = Qux> { + | ^^^^^^^ associated type not allowed here + | +help: to use `Qux` as a generic argument specify it directly | -LL | fn baz(x: &>::A) {} - | ^^^^^ associated type not allowed here +LL | impl<'a, T> St<'a , Qux> { + | ~~~ -error: aborting due to 1 previous error +error: aborting due to 27 previous errors -For more information about this error, try `rustc --explain E0229`. +Some errors have detailed explanations: E0046, E0107, E0229, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr index fb0e63c207a54..8d40e6905e07f 100644 --- a/tests/ui/associated-types/issue-25700.stderr +++ b/tests/ui/associated-types/issue-25700.stderr @@ -12,7 +12,10 @@ note: if `S<()>` implemented `Clone`, you could clone the value --> $DIR/issue-25700.rs:1:1 | LL | struct S(#[allow(dead_code)] Option<&'static T>); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(t); + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/async-await/async-drop.rs b/tests/ui/async-await/async-drop.rs new file mode 100644 index 0000000000000..6d02dcebc0b65 --- /dev/null +++ b/tests/ui/async-await/async-drop.rs @@ -0,0 +1,197 @@ +//@ run-pass +//@ check-run-results + +#![feature(async_drop, impl_trait_in_assoc_type, noop_waker, async_closure)] +#![allow(incomplete_features, dead_code)] + +//@ edition: 2021 + +// FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests +use core::future::{async_drop_in_place, AsyncDrop, Future}; +use core::hint::black_box; +use core::mem::{self, ManuallyDrop}; +use core::pin::{pin, Pin}; +use core::task::{Context, Poll, Waker}; + +async fn test_async_drop(x: T) { + let mut x = mem::MaybeUninit::new(x); + let dtor = pin!(unsafe { async_drop_in_place(x.as_mut_ptr()) }); + test_idempotency(dtor).await; +} + +fn test_idempotency(mut x: Pin<&mut T>) -> impl Future + '_ +where + T: Future, +{ + core::future::poll_fn(move |cx| { + assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); + assert_eq!(x.as_mut().poll(cx), Poll::Ready(())); + Poll::Ready(()) + }) +} + +fn main() { + let waker = Waker::noop(); + let mut cx = Context::from_waker(&waker); + + let i = 13; + let fut = pin!(async { + test_async_drop(Int(0)).await; + test_async_drop(AsyncInt(0)).await; + test_async_drop([AsyncInt(1), AsyncInt(2)]).await; + test_async_drop((AsyncInt(3), AsyncInt(4))).await; + test_async_drop(5).await; + let j = 42; + test_async_drop(&i).await; + test_async_drop(&j).await; + test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }).await; + test_async_drop(ManuallyDrop::new(AsyncInt(9))).await; + + let foo = AsyncInt(10); + test_async_drop(AsyncReference { foo: &foo }).await; + + let foo = AsyncInt(11); + test_async_drop(|| { + black_box(foo); + let foo = AsyncInt(10); + foo + }).await; + + test_async_drop(AsyncEnum::A(AsyncInt(12))).await; + test_async_drop(AsyncEnum::B(SyncInt(13))).await; + + test_async_drop(SyncInt(14)).await; + test_async_drop(SyncThenAsync { + i: 15, + a: AsyncInt(16), + b: SyncInt(17), + c: AsyncInt(18), + }).await; + + let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19))); + test_idempotency(async_drop_fut).await; + + let foo = AsyncInt(20); + test_async_drop(async || { + black_box(foo); + let foo = AsyncInt(19); + // Await point there, but this is async closure so it's fine + black_box(core::future::ready(())).await; + foo + }).await; + + test_async_drop(AsyncUnion { signed: 21 }).await; + }); + let res = fut.poll(&mut cx); + assert_eq!(res, Poll::Ready(())); +} + +struct AsyncInt(i32); + +impl AsyncDrop for AsyncInt { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncInt::Dropper::poll: {}", self.0); + } + } +} + +struct SyncInt(i32); + +impl Drop for SyncInt { + fn drop(&mut self) { + println!("SyncInt::drop: {}", self.0); + } +} + +struct SyncThenAsync { + i: i32, + a: AsyncInt, + b: SyncInt, + c: AsyncInt, +} + +impl Drop for SyncThenAsync { + fn drop(&mut self) { + println!("SyncThenAsync::drop: {}", self.i); + } +} + +struct AsyncReference<'a> { + foo: &'a AsyncInt, +} + +impl AsyncDrop for AsyncReference<'_> { + type Dropper<'a> = impl Future where Self: 'a; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncReference::Dropper::poll: {}", self.foo.0); + } + } +} + +struct Int(i32); + +struct AsyncStruct { + i: i32, + a: AsyncInt, + b: AsyncInt, +} + +impl AsyncDrop for AsyncStruct { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!("AsyncStruct::Dropper::poll: {}", self.i); + } + } +} + +enum AsyncEnum { + A(AsyncInt), + B(SyncInt), +} + +impl AsyncDrop for AsyncEnum { + type Dropper<'a> = impl Future; + + fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + let new_self = match &*self { + AsyncEnum::A(foo) => { + println!("AsyncEnum(A)::Dropper::poll: {}", foo.0); + AsyncEnum::B(SyncInt(foo.0)) + } + AsyncEnum::B(foo) => { + println!("AsyncEnum(B)::Dropper::poll: {}", foo.0); + AsyncEnum::A(AsyncInt(foo.0)) + } + }; + mem::forget(mem::replace(&mut *self, new_self)); + } + } +} + +// FIXME(zetanumbers): Disallow types with `AsyncDrop` in unions +union AsyncUnion { + signed: i32, + unsigned: u32, +} + +impl AsyncDrop for AsyncUnion { + type Dropper<'a> = impl Future; + + fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { + async move { + println!( + "AsyncUnion::Dropper::poll: {}, {}", + unsafe { self.signed }, + unsafe { self.unsigned }, + ); + } + } +} diff --git a/tests/ui/async-await/async-drop.run.stdout b/tests/ui/async-await/async-drop.run.stdout new file mode 100644 index 0000000000000..9cae4331caf92 --- /dev/null +++ b/tests/ui/async-await/async-drop.run.stdout @@ -0,0 +1,22 @@ +AsyncInt::Dropper::poll: 0 +AsyncInt::Dropper::poll: 1 +AsyncInt::Dropper::poll: 2 +AsyncInt::Dropper::poll: 3 +AsyncInt::Dropper::poll: 4 +AsyncStruct::Dropper::poll: 6 +AsyncInt::Dropper::poll: 7 +AsyncInt::Dropper::poll: 8 +AsyncReference::Dropper::poll: 10 +AsyncInt::Dropper::poll: 11 +AsyncEnum(A)::Dropper::poll: 12 +SyncInt::drop: 12 +AsyncEnum(B)::Dropper::poll: 13 +AsyncInt::Dropper::poll: 13 +SyncInt::drop: 14 +SyncThenAsync::drop: 15 +AsyncInt::Dropper::poll: 16 +SyncInt::drop: 17 +AsyncInt::Dropper::poll: 18 +AsyncInt::Dropper::poll: 19 +AsyncInt::Dropper::poll: 20 +AsyncUnion::Dropper::poll: 21, 21 diff --git a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr index b0677a83864e0..d7caf6b3c0d21 100644 --- a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr +++ b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/async-outside-of-await-issue-121096.rs:7:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr index d99967eb23ca6..8cea73f865148 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:7:20 diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr index bf5c4d8d6aab3..70b7fa52a19c7 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:10:20 diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 928eb0b821db1..a98bb0764c0e6 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -141,7 +141,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:68:19 | LL | fn foo13() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await(); | ^^^^^ only allowed inside `async` functions and blocks @@ -149,7 +149,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:73:19 | LL | fn foo14() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await()?; | ^^^^^ only allowed inside `async` functions and blocks @@ -157,7 +157,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:78:19 | LL | fn foo15() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await; | ^^^^^ only allowed inside `async` functions and blocks @@ -165,7 +165,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:82:19 | LL | fn foo16() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks @@ -173,7 +173,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:87:23 | LL | fn foo() -> Result<(), ()> { - | --- this is not `async` + | -------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/coroutine-not-future.rs b/tests/ui/async-await/coroutine-not-future.rs index 2993f58378a44..4522743550785 100644 --- a/tests/ui/async-await/coroutine-not-future.rs +++ b/tests/ui/async-await/coroutine-not-future.rs @@ -1,5 +1,5 @@ //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::future::Future; use std::ops::Coroutine; @@ -9,6 +9,7 @@ fn returns_async_block() -> impl Future { async {} } fn returns_coroutine() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { let _: () = yield (); } @@ -23,9 +24,12 @@ fn main() { takes_future(returns_async_block()); takes_future(async {}); takes_coroutine(returns_coroutine()); - takes_coroutine(|| { - let _: () = yield (); - }); + takes_coroutine( + #[coroutine] + || { + let _: () = yield (); + }, + ); // async futures are not coroutines: takes_coroutine(async_fn()); @@ -38,8 +42,11 @@ fn main() { // coroutines are not futures: takes_future(returns_coroutine()); //~^ ERROR is not a future - takes_future(|ctx| { - //~^ ERROR is not a future - ctx = yield (); - }); + takes_future( + #[coroutine] + |ctx| { + //~^ ERROR is not a future + ctx = yield (); + }, + ); } diff --git a/tests/ui/async-await/coroutine-not-future.stderr b/tests/ui/async-await/coroutine-not-future.stderr index 580217fb4f821..403e547a7538e 100644 --- a/tests/ui/async-await/coroutine-not-future.stderr +++ b/tests/ui/async-await/coroutine-not-future.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `impl Future: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:31:21 + --> $DIR/coroutine-not-future.rs:35:21 | LL | takes_coroutine(async_fn()); | --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future` @@ -7,13 +7,13 @@ LL | takes_coroutine(async_fn()); | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine(_g: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` error[E0277]: the trait bound `impl Future: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:33:21 + --> $DIR/coroutine-not-future.rs:37:21 | LL | takes_coroutine(returns_async_block()); | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future` @@ -21,27 +21,27 @@ LL | takes_coroutine(returns_async_block()); | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine(_g: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` -error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:35:21 +error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}: Coroutine<_>` is not satisfied + --> $DIR/coroutine-not-future.rs:39:21 | LL | takes_coroutine(async {}); - | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}` + | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}` | | | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine(_g: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` error[E0277]: `impl Coroutine` is not a future - --> $DIR/coroutine-not-future.rs:39:18 + --> $DIR/coroutine-not-future.rs:43:18 | LL | takes_future(returns_coroutine()); | ------------ ^^^^^^^^^^^^^^^^^^^ `impl Coroutine` is not a future @@ -50,26 +50,26 @@ LL | takes_future(returns_coroutine()); | = help: the trait `Future` is not implemented for `impl Coroutine` note: required by a bound in `takes_future` - --> $DIR/coroutine-not-future.rs:17:26 + --> $DIR/coroutine-not-future.rs:18:26 | LL | fn takes_future(_f: impl Future) {} | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` -error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future - --> $DIR/coroutine-not-future.rs:41:18 +error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future + --> $DIR/coroutine-not-future.rs:47:9 | -LL | takes_future(|ctx| { - | _____------------_^ - | | | - | | required by a bound introduced by this call +LL | takes_future( + | ------------ required by a bound introduced by this call +LL | #[coroutine] +LL | / |ctx| { LL | | -LL | | ctx = yield (); -LL | | }); - | |_____^ `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future +LL | | ctx = yield (); +LL | | }, + | |_________^ `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future | - = help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` + = help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` note: required by a bound in `takes_future` - --> $DIR/coroutine-not-future.rs:17:26 + --> $DIR/coroutine-not-future.rs:18:26 | LL | fn takes_future(_f: impl Future) {} | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` diff --git a/tests/ui/async-await/inference_var_self_argument.rs b/tests/ui/async-await/inference_var_self_argument.rs index f4bb8884b0587..4d5ac4abb199b 100644 --- a/tests/ui/async-await/inference_var_self_argument.rs +++ b/tests/ui/async-await/inference_var_self_argument.rs @@ -4,7 +4,7 @@ trait Foo { async fn foo(self: &dyn Foo) { //~^ ERROR: `Foo` cannot be made into an object - //~| ERROR invalid `self` parameter type: &dyn Foo + //~| ERROR invalid `self` parameter type: `&dyn Foo` todo!() } } diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index 8a8c1ea03f14a..f94ae2a27c33e 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -13,7 +13,7 @@ LL | async fn foo(self: &dyn Foo) { | ^^^ ...because method `foo` is `async` = help: consider moving `foo` to another trait -error[E0307]: invalid `self` parameter type: &dyn Foo +error[E0307]: invalid `self` parameter type: `&dyn Foo` --> $DIR/inference_var_self_argument.rs:5:24 | LL | async fn foo(self: &dyn Foo) { diff --git a/tests/ui/async-await/issue-66312.stderr b/tests/ui/async-await/issue-66312.stderr index 2875af8a97e04..702e0b375e577 100644 --- a/tests/ui/async-await/issue-66312.stderr +++ b/tests/ui/async-await/issue-66312.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | if x.is_some() { | ^^^^^^^^^^^ expected `bool`, found `()` -error[E0307]: invalid `self` parameter type: T +error[E0307]: invalid `self` parameter type: `T` --> $DIR/issue-66312.rs:4:22 | LL | fn is_some(self: T); diff --git a/tests/ui/async-await/issues/issue-51751.stderr b/tests/ui/async-await/issues/issue-51751.stderr index ba256b19948c0..ab12e0427b47a 100644 --- a/tests/ui/async-await/issues/issue-51751.stderr +++ b/tests/ui/async-await/issues/issue-51751.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:9:27 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let result = inc(10000); LL | let finished = result.await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-1.stderr b/tests/ui/async-await/issues/issue-62009-1.stderr index 02933f4f2f233..f8a4b5d9af8b2 100644 --- a/tests/ui/async-await/issues/issue-62009-1.stderr +++ b/tests/ui/async-await/issues/issue-62009-1.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:6:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | async { let (); }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -10,7 +10,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:10:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -19,7 +19,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:12:16 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | (|_| 2333).await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-2.stderr b/tests/ui/async-await/issues/issue-62009-2.stderr index 80a831cc5475f..0004f99f9018d 100644 --- a/tests/ui/async-await/issues/issue-62009-2.stderr +++ b/tests/ui/async-await/issues/issue-62009-2.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-2.rs:8:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | (async || 2333)().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs b/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs index f937311a5a0f7..6b7dfc1235e8e 100644 --- a/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs +++ b/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs @@ -6,15 +6,13 @@ //@ error-pattern:coroutine resumed after completion //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::{ - ops::Coroutine, - pin::Pin, -}; +use std::{ops::Coroutine, pin::Pin}; fn main() { - let mut g = || { + let mut g = #[coroutine] + || { yield; }; Pin::new(&mut g).resume(()); // Yields once. diff --git a/tests/ui/async-await/issues/non-async-enclosing-span.stderr b/tests/ui/async-await/issues/non-async-enclosing-span.stderr index 91a9e5aa6cabf..9c26de1c5047c 100644 --- a/tests/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/tests/ui/async-await/issues/non-async-enclosing-span.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/non-async-enclosing-span.rs:9:28 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let x = move || {}; LL | let y = do_the_thing().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/non-trivial-drop.rs b/tests/ui/async-await/non-trivial-drop.rs index 71b8812421972..95de3c5b0054d 100644 --- a/tests/ui/async-await/non-trivial-drop.rs +++ b/tests/ui/async-await/non-trivial-drop.rs @@ -8,7 +8,7 @@ fn main() { } fn foo() { - || { + #[coroutine] || { yield drop(Config { nickname: NonCopy, b: NonCopy2, diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.rs b/tests/ui/attributes/collapse-debuginfo-invalid.rs index 42d8982c11861..d6b3554a5a812 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.rs +++ b/tests/ui/attributes/collapse-debuginfo-invalid.rs @@ -1,84 +1,83 @@ -#![feature(collapse_debuginfo)] #![feature(stmt_expr_attributes)] #![feature(type_alias_impl_trait)] #![no_std] // Test that the `#[collapse_debuginfo]` attribute can only be used on macro definitions. -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions extern crate std; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions use std::collections::HashMap; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions static FOO: u32 = 3; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions const BAR: u32 = 3; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions fn foo() { - let _ = #[collapse_debuginfo] || { }; + let _ = #[collapse_debuginfo(yes)] || { }; //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions let _ = 3; - let _ = #[collapse_debuginfo] 3; + let _ = #[collapse_debuginfo(yes)] 3; //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions match (3, 4) { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions _ => (), } } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions mod bar { } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type Map = HashMap; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions enum Foo { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions Variant, } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions struct Bar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions field: u32, } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions union Qux { a: u32, b: u16 } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions trait Foobar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type Bar; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type AFoobar = impl Foobar; @@ -90,19 +89,19 @@ fn constraining() -> AFoobar { Bar { field: 3 } } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions impl Bar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions const FOO: u32 = 3; - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions fn bar(&self) {} } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! finally { ($e:expr) => { $e } } diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.stderr b/tests/ui/attributes/collapse-debuginfo-invalid.stderr index 01c476091082f..7cbbd1d647e71 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.stderr +++ b/tests/ui/attributes/collapse-debuginfo-invalid.stderr @@ -1,152 +1,152 @@ error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:8:1 + --> $DIR/collapse-debuginfo-invalid.rs:7:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | extern crate std; | ----------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:12:1 + --> $DIR/collapse-debuginfo-invalid.rs:11:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | use std::collections::HashMap; | ------------------------------ not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:16:1 + --> $DIR/collapse-debuginfo-invalid.rs:15:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | static FOO: u32 = 3; | -------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:20:1 + --> $DIR/collapse-debuginfo-invalid.rs:19:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const BAR: u32 = 3; | ------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:24:1 + --> $DIR/collapse-debuginfo-invalid.rs:23:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / fn foo() { -LL | | let _ = #[collapse_debuginfo] || { }; +LL | | let _ = #[collapse_debuginfo(yes)] || { }; LL | | -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] ... | LL | | } LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:27:13 + --> $DIR/collapse-debuginfo-invalid.rs:26:13 | -LL | let _ = #[collapse_debuginfo] || { }; - | ^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition +LL | let _ = #[collapse_debuginfo(yes)] || { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:29:5 + --> $DIR/collapse-debuginfo-invalid.rs:28:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | let _ = 3; | ---------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:32:13 + --> $DIR/collapse-debuginfo-invalid.rs:31:13 | -LL | let _ = #[collapse_debuginfo] 3; - | ^^^^^^^^^^^^^^^^^^^^^ - not a macro definition +LL | let _ = #[collapse_debuginfo(yes)] 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:35:9 + --> $DIR/collapse-debuginfo-invalid.rs:34:9 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | _ => (), | ------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:41:1 + --> $DIR/collapse-debuginfo-invalid.rs:40:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / mod bar { LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:46:1 + --> $DIR/collapse-debuginfo-invalid.rs:45:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type Map = HashMap; | ----------------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:50:1 + --> $DIR/collapse-debuginfo-invalid.rs:49:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / enum Foo { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | Variant, LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:53:5 + --> $DIR/collapse-debuginfo-invalid.rs:52:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | Variant, | ------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:58:1 + --> $DIR/collapse-debuginfo-invalid.rs:57:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / struct Bar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | field: u32, LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:61:5 + --> $DIR/collapse-debuginfo-invalid.rs:60:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | field: u32, | ---------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:66:1 + --> $DIR/collapse-debuginfo-invalid.rs:65:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / union Qux { LL | | a: u32, @@ -155,35 +155,35 @@ LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:73:1 + --> $DIR/collapse-debuginfo-invalid.rs:72:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / trait Foobar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | type Bar; LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:81:1 + --> $DIR/collapse-debuginfo-invalid.rs:80:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type AFoobar = impl Foobar; | --------------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:93:1 + --> $DIR/collapse-debuginfo-invalid.rs:92:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / impl Bar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | const FOO: u32 = 3; ... | @@ -192,28 +192,28 @@ LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:76:5 + --> $DIR/collapse-debuginfo-invalid.rs:75:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type Bar; | --------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:96:5 + --> $DIR/collapse-debuginfo-invalid.rs:95:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const FOO: u32 = 3; | ------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:100:5 + --> $DIR/collapse-debuginfo-invalid.rs:99:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn bar(&self) {} | ---------------- not a macro definition diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs new file mode 100644 index 0000000000000..7f95fa7ebbece --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs new file mode 100644 index 0000000000000..d96e8b8ef8436 --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs index db3407a7d55fc..3e63349edb747 100644 --- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs +++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs @@ -1,14 +1,29 @@ +//@ ignore-cross-compile because aux-bin does not yet support it +//@ only-unix because SIGPIPE is a unix thing +//@ aux-bin: assert-inherit-sig_dfl.rs +//@ aux-bin: assert-inherit-sig_ign.rs //@ run-pass -//@ aux-build:sigpipe-utils.rs -#![feature(unix_sigpipe)] +#![feature(rustc_private, unix_sigpipe)] -#[unix_sigpipe = "inherit"] +extern crate libc; + +// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec'ing child +// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See +// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384 +#[unix_sigpipe = "sig_dfl"] fn main() { - extern crate sigpipe_utils; + // First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"]. + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl"); + + // With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN. + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + } + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_ign"); +} - // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored, - // instead the default handler shall be installed. (We assume that the - // process that runs these tests have the default handler.) - sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +fn assert_inherit_sigpipe_disposition(aux_bin: &str) { + let mut cmd = std::process::Command::new(aux_bin); + assert!(cmd.status().unwrap().success()); } diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr index dcf1c02bceefa..4c1de72798c45 100644 --- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr +++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr @@ -23,6 +23,13 @@ LL | fn copy(x: T) -> (T, T) { (x, x) } | | value moved here | move occurs because `x` has type `T`, which does not implement the `Copy` trait | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:8:9 + | +LL | fn copy(x: T) -> (T, T) { (x, x) } + | ^ - you could clone this value + | | + | consider constraining this type parameter with `Clone` help: consider further restricting this bound | LL | fn copy(x: T) -> (T, T) { (x, x) } diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr index 6fbbb55437eb2..1b59216b3c76c 100644 --- a/tests/ui/binop/binop-consume-args.stderr +++ b/tests/ui/binop/binop-consume-args.stderr @@ -8,6 +8,13 @@ LL | lhs + rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:5:8 + | +LL | fn add, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs + rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -26,6 +33,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:5:30 + | +LL | fn add, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs + rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn add, B: Copy>(lhs: A, rhs: B) { @@ -41,6 +55,13 @@ LL | lhs - rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:11:8 + | +LL | fn sub, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs - rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -59,6 +80,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:11:30 + | +LL | fn sub, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs - rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn sub, B: Copy>(lhs: A, rhs: B) { @@ -74,6 +102,13 @@ LL | lhs * rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:17:8 + | +LL | fn mul, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs * rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -92,6 +127,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:17:30 + | +LL | fn mul, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs * rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn mul, B: Copy>(lhs: A, rhs: B) { @@ -107,6 +149,13 @@ LL | lhs / rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:23:8 + | +LL | fn div, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs / rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -125,6 +174,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:23:30 + | +LL | fn div, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs / rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn div, B: Copy>(lhs: A, rhs: B) { @@ -140,6 +196,13 @@ LL | lhs % rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:29:8 + | +LL | fn rem, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs % rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -158,6 +221,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:29:30 + | +LL | fn rem, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs % rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn rem, B: Copy>(lhs: A, rhs: B) { @@ -173,6 +243,13 @@ LL | lhs & rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:35:11 + | +LL | fn bitand, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs & rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -191,6 +268,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:35:36 + | +LL | fn bitand, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs & rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitand, B: Copy>(lhs: A, rhs: B) { @@ -206,6 +290,13 @@ LL | lhs | rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:41:10 + | +LL | fn bitor, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs | rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -224,6 +315,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:41:34 + | +LL | fn bitor, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs | rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitor, B: Copy>(lhs: A, rhs: B) { @@ -239,6 +337,13 @@ LL | lhs ^ rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:47:11 + | +LL | fn bitxor, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs ^ rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -257,6 +362,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:47:36 + | +LL | fn bitxor, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs ^ rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitxor, B: Copy>(lhs: A, rhs: B) { @@ -272,6 +384,13 @@ LL | lhs << rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:53:8 + | +LL | fn shl, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs << rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -290,6 +409,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:53:30 + | +LL | fn shl, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs << rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn shl, B: Copy>(lhs: A, rhs: B) { @@ -305,6 +431,13 @@ LL | lhs >> rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:59:8 + | +LL | fn shr, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs >> rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -323,6 +456,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:59:30 + | +LL | fn shr, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs >> rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn shr, B: Copy>(lhs: A, rhs: B) { diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr index 1dd8c9a87d472..83c27590e9014 100644 --- a/tests/ui/binop/binop-move-semantics.stderr +++ b/tests/ui/binop/binop-move-semantics.stderr @@ -11,6 +11,13 @@ LL | | x; | |_____value used here after move | `x` moved due to usage in operator | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:5:16 + | +LL | fn double_move>(x: T) { + | ^ consider constraining this type parameter with `Clone` +LL | x + | - you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -51,6 +58,14 @@ LL | x ... LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:17:18 + | +LL | fn move_borrowed>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; + | -- you could clone this value error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/binop-move-semantics.rs:23:5 @@ -65,6 +80,15 @@ LL | y; | ^ move out of `y` occurs here LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:17:18 + | +LL | fn move_borrowed>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; +LL | let n = &mut y; + | ------ you could clone this value error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/binop-move-semantics.rs:30:5 @@ -80,12 +104,29 @@ LL | | *n; | note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:26:24 + | +LL | fn illegal_dereference>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | *m + | -- you could clone this value error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/binop-move-semantics.rs:32:5 | LL | *n; | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:26:24 + | +LL | fn illegal_dereference>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | *n; + | -- you could clone this value error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable --> $DIR/binop-move-semantics.rs:54:5 diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr index dd22d7e2e2ed2..98ffa7f6ffa75 100644 --- a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr +++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr @@ -2,56 +2,86 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:14:13 | LL | x => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | mut x => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | ref mut x => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:20:13 | LL | E::Foo(x) => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | E::Foo(mut x) => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | E::Foo(ref mut x) => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:26:13 | LL | S { bar: x } => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | S { bar: mut x } => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | S { bar: ref mut x } => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:32:13 | LL | (x,) => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | (mut x,) => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | (ref mut x,) => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 | LL | [x,_,_] => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | [mut x,_,_] => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | [ref mut x,_,_] => { + | ~~~~~~~~~ error: aborting due to 5 previous errors diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr index 01647011207f4..9915acfe06537 100644 --- a/tests/ui/borrowck/borrowck-move-by-capture.stderr +++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr @@ -11,6 +11,12 @@ LL | let _h = to_fn_once(move || -> isize { *bar }); | | variable moved due to use in closure | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait | `bar` is moved here + | +help: clone the value before moving it into the closure + | +LL ~ let value = bar.clone(); +LL ~ let _h = to_fn_once(move || -> isize { value }); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr index 86bddacbdc727..b4b60d40d9143 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/borrowck-move-out-of-static-item.rs:3:1 | LL | struct Foo { - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | test(BAR); + | --- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr index 4d9477f85811d..cc6c3bdeb1022 100644 --- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr +++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr @@ -14,7 +14,10 @@ note: if `S` implemented `Clone`, you could clone the value --> $DIR/borrowck-move-subcomponent.rs:6:1 | LL | struct S { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let pb = &a; + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr index 1602058c183fc..c3b7b0b6080c6 100644 --- a/tests/ui/borrowck/borrowck-overloaded-call.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr @@ -34,7 +34,10 @@ note: if `SFnOnce` implemented `Clone`, you could clone the value --> $DIR/borrowck-overloaded-call.rs:41:1 | LL | struct SFnOnce { - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | s(" world".to_string()); + | - you could clone this value error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr index f0eaf4bac7dfa..19f040556f8ae 100644 --- a/tests/ui/borrowck/clone-on-ref.stderr +++ b/tests/ui/borrowck/clone-on-ref.stderr @@ -32,6 +32,13 @@ LL | LL | println!("{b}"); | --- borrow later used here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/clone-on-ref.rs:11:8 + | +LL | fn bar(x: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let a = &x; + | -- you could clone this value help: consider further restricting this bound | LL | fn bar(x: T) { @@ -56,7 +63,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/clone-on-ref.rs:19:1 | LL | struct A; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +LL | fn qux(x: A) { +LL | let a = &x; + | -- you could clone this value help: consider annotating `A` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr index b4775496f4f48..a894fa63ace28 100644 --- a/tests/ui/borrowck/issue-101119.stderr +++ b/tests/ui/borrowck/issue-101119.stderr @@ -22,7 +22,10 @@ note: if `State` implemented `Clone`, you could clone the value --> $DIR/issue-101119.rs:1:1 | LL | struct State; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | fill_segment(state); + | ----- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr index 94421c35c65d2..603055beadcef 100644 --- a/tests/ui/borrowck/issue-103624.stderr +++ b/tests/ui/borrowck/issue-103624.stderr @@ -13,8 +13,11 @@ LL | self.b; note: if `StructB` implemented `Clone`, you could clone the value --> $DIR/issue-103624.rs:23:1 | +LL | self.b; + | ------ you could clone this value +... LL | struct StructB {} - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type error[E0521]: borrowed data escapes outside of method --> $DIR/issue-103624.rs:14:9 diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr index 701f00d079d38..dde17d1f6523c 100644 --- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr +++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr @@ -15,7 +15,10 @@ note: if `Example` implemented `Clone`, you could clone the value --> $DIR/issue-119915-bad-clone-suggestion.rs:3:1 | LL | struct Example(PhantomData<(fn(E), fn(FakeParam))>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | unsafe { self.change() } + | ---- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr index e2c3a9d5a2663..057ac6d7e3df9 100644 --- a/tests/ui/borrowck/issue-17718-static-move.stderr +++ b/tests/ui/borrowck/issue-17718-static-move.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/issue-17718-static-move.rs:1:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _a = FOO; + | --- you could clone this value help: consider borrowing here | LL | let _a = &FOO; diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 1da6f0bef0234..20a4bd4e42378 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -23,7 +23,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = unsafe { *mut_ref() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let a = unsafe { *mut_ref() }; @@ -40,7 +43,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = unsafe { *imm_ref() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let b = unsafe { *imm_ref() }; @@ -57,7 +63,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let c = unsafe { *mut_ptr() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let c = unsafe { *mut_ptr() }; @@ -74,7 +83,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let d = unsafe { *const_ptr() }; + | ------------ you could clone this value help: consider removing the dereference here | LL - let d = unsafe { *const_ptr() }; diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr index 43f4e820857a0..1e9b1d5209cb6 100644 --- a/tests/ui/borrowck/move-error-in-promoted-2.stderr +++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr @@ -11,7 +11,10 @@ note: if `S` implemented `Clone`, you could clone the value --> $DIR/move-error-in-promoted-2.rs:3:1 | LL | struct S; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | &([S][0],); + | ------ you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr index 40b64398aef6a..97d140515184a 100644 --- a/tests/ui/borrowck/move-error-snippets.stderr +++ b/tests/ui/borrowck/move-error-snippets.stderr @@ -13,7 +13,12 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-error-snippets.rs:9:1 | LL | struct A; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type + | + ::: $DIR/move-error-snippets-ext.rs:5:17 + | +LL | let a = $c; + | -- you could clone this value = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider borrowing here | diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr index a4e70b506462d..009e85a8031ee 100644 --- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr +++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 | LL | struct Foo(usize); - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | static Y: usize = get(*&X); + | --- you could clone this value error[E0507]: cannot move out of a shared reference --> $DIR/move-in-static-initializer-issue-38520.rs:13:22 @@ -20,7 +23,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 | LL | struct Foo(usize); - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | const Z: usize = get(*&X); + | --- you could clone this value error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs b/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs new file mode 100644 index 0000000000000..fb894623e7804 --- /dev/null +++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs @@ -0,0 +1,11 @@ +fn main() { + let y = Some(0); + if let Some(x) = y { + x = 2; //~ ERROR cannot assign twice to immutable variable `x` + } + + let mut arr = [1, 2, 3]; + let [x, ref xs_hold @ ..] = arr; + x = 0; //~ ERROR cannot assign twice to immutable variable `x` + eprintln!("{:?}", arr); +} diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr new file mode 100644 index 0000000000000..fd2a775a099cb --- /dev/null +++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr @@ -0,0 +1,37 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/suggest-ref-mut-issue-118596.rs:4:9 + | +LL | if let Some(x) = y { + | - first assignment to `x` +LL | x = 2; + | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | if let Some(mut x) = y { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | if let Some(ref mut x) = y { + | ~~~~~~~~~ + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/suggest-ref-mut-issue-118596.rs:9:5 + | +LL | let [x, ref xs_hold @ ..] = arr; + | - first assignment to `x` +LL | x = 0; + | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let [mut x, ref xs_hold @ ..] = arr; + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let [ref mut x, ref xs_hold @ ..] = arr; + | ~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr index 53ff5f0107df3..bdaa9449f913e 100644 --- a/tests/ui/box/leak-alloc.stderr +++ b/tests/ui/box/leak-alloc.stderr @@ -16,7 +16,10 @@ note: if `Alloc` implemented `Clone`, you could clone the value --> $DIR/leak-alloc.rs:8:1 | LL | struct Alloc {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let boxed = Box::new_in(10, alloc.by_ref()); + | ----- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs index 410e15d024fab..0d8f92f013fba 100644 --- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs @@ -17,7 +17,7 @@ impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { - let foo_e : *const dyn Foo = t as *const _; + let foo_e : *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) diff --git a/tests/ui/closures/deduce-signature/deduce-from-opaque-type-after-norm.rs b/tests/ui/closures/deduce-signature/deduce-from-opaque-type-after-norm.rs new file mode 100644 index 0000000000000..9885d381d244d --- /dev/null +++ b/tests/ui/closures/deduce-signature/deduce-from-opaque-type-after-norm.rs @@ -0,0 +1,11 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +trait Foo { + fn test() -> impl Fn(u32) -> u32 { + |x| x.count_ones() + } +} + +fn main() {} diff --git a/tests/ui/closures/deduce-signature/deduce-from-opaque-type.rs b/tests/ui/closures/deduce-signature/deduce-from-opaque-type.rs new file mode 100644 index 0000000000000..3185a431f0bad --- /dev/null +++ b/tests/ui/closures/deduce-signature/deduce-from-opaque-type.rs @@ -0,0 +1,9 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +fn foo() -> impl FnOnce(u32) -> u32 { + |x| x.leading_zeros() +} + +fn main() {} diff --git a/tests/ui/closures/deduce-signature/infer-higher-ranked-signature.rs b/tests/ui/closures/deduce-signature/infer-higher-ranked-signature.rs new file mode 100644 index 0000000000000..d9ab0149087e2 --- /dev/null +++ b/tests/ui/closures/deduce-signature/infer-higher-ranked-signature.rs @@ -0,0 +1,20 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +trait Foo {} +fn needs_foo(_: T) +where + Wrap: Foo, +{ +} + +struct Wrap(T); +impl Foo for Wrap where T: for<'a> Fn(&'a i32) {} + +fn main() { + needs_foo(|x| { + x.to_string(); + }); +} diff --git a/tests/ui/closures/infer-signature-from-impl.rs b/tests/ui/closures/deduce-signature/infer-signature-from-impl.rs similarity index 79% rename from tests/ui/closures/infer-signature-from-impl.rs rename to tests/ui/closures/deduce-signature/infer-signature-from-impl.rs index fa455c15ec794..20802ce37ee69 100644 --- a/tests/ui/closures/infer-signature-from-impl.rs +++ b/tests/ui/closures/deduce-signature/infer-signature-from-impl.rs @@ -1,8 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] known-bug: trait-system-refactor-initiative#71 -//@[current] check-pass +//@ check-pass trait Foo {} fn needs_foo(_: T) diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr new file mode 100644 index 0000000000000..eaa0d32e75dff --- /dev/null +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr @@ -0,0 +1,15 @@ +error: implementation of `Foo` is not general enough + --> $DIR/obligation-with-leaking-placeholders.rs:18:5 + | +LL | / needs_foo(|x| { +LL | | +LL | | +LL | | x.to_string(); +LL | | }); + | |______^ implementation of `Foo` is not general enough + | + = note: `Wrap<{closure@$DIR/obligation-with-leaking-placeholders.rs:18:15: 18:18}>` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1` + +error: aborting due to 1 previous error + diff --git a/tests/ui/closures/infer-signature-from-impl.next.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr similarity index 87% rename from tests/ui/closures/infer-signature-from-impl.next.stderr rename to tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr index 332917eaaff04..3d667f12371ab 100644 --- a/tests/ui/closures/infer-signature-from-impl.next.stderr +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr @@ -1,8 +1,9 @@ error[E0282]: type annotations needed - --> $DIR/infer-signature-from-impl.rs:18:16 + --> $DIR/obligation-with-leaking-placeholders.rs:18:16 | LL | needs_foo(|x| { | ^ +... LL | x.to_string(); | - type must be known at this point | diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs new file mode 100644 index 0000000000000..deb888ec28673 --- /dev/null +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.rs @@ -0,0 +1,23 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// See #124385 for more details. + +trait Foo<'a> {} +fn needs_foo(_: T) +where + for<'a> Wrap: Foo<'a>, +{ +} + +struct Wrap(T); +impl<'a, T> Foo<'a> for Wrap where T: Fn(&'a i32) {} + +fn main() { + needs_foo(|x| { + //[current]~^ implementation of `Foo` is not general enough + //[next]~^^ ERROR type annotations needed + x.to_string(); + }); +} diff --git a/tests/ui/closures/issue-23012-supertrait-signature-inference.rs b/tests/ui/closures/deduce-signature/supertrait-signature-inference-issue-23012.rs similarity index 84% rename from tests/ui/closures/issue-23012-supertrait-signature-inference.rs rename to tests/ui/closures/deduce-signature/supertrait-signature-inference-issue-23012.rs index 732f687309ce4..16890b28acd86 100644 --- a/tests/ui/closures/issue-23012-supertrait-signature-inference.rs +++ b/tests/ui/closures/deduce-signature/supertrait-signature-inference-issue-23012.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // Checks that we can infer a closure signature even if the `FnOnce` bound is // a supertrait of the obligations we have currently registered for the Ty var. diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.rs b/tests/ui/codemap_tests/huge_multispan_highlight.rs index c2bd393589e01..28c595cca6425 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.rs +++ b/tests/ui/codemap_tests/huge_multispan_highlight.rs @@ -1,7 +1,5 @@ //@ compile-flags: --error-format=human --color=always //@ ignore-windows -// Temporary until next release: -//@ ignore-stage2 fn main() { let _ = match true { true => ( diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.svg b/tests/ui/codemap_tests/huge_multispan_highlight.svg index f26a2bd7275b6..7b6dbb17c6f95 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.svg +++ b/tests/ui/codemap_tests/huge_multispan_highlight.svg @@ -1,4 +1,4 @@ - + >::Assoc, U> +where + T: dep::Trait, + ::Assoc: Trait, +{ + type Assoc = U; +} + +fn main() {} diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr new file mode 100644 index 0000000000000..d83a56c0bd0ea --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6 + | +LL | impl foreign::Trait1 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr new file mode 100644 index 0000000000000..d83a56c0bd0ea --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6 + | +LL | impl foreign::Trait1 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.rs b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.rs new file mode 100644 index 0000000000000..227d8535232df --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.rs @@ -0,0 +1,29 @@ +// This test demonstrates a limitation of the trait solver. +// Basically, one might think that `T` was covered by the projection since the +// latter appears to normalize to a local type. However, since we instantiate the +// constituent types of the self type of impls with fresh infer vars and try to +// normalize them during orphan checking, we wind up trying to normalize a +// projection whose self type is an infer var which unconditionally fails due to +// ambiguity. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ check-pass +//@ compile-flags: --crate-type=lib +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +trait Project { type Output; } + +impl Project for T { + type Output = Local; +} + +struct Local; + +impl foreign::Trait1 for ::Output {} +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr new file mode 100644 index 0000000000000..8964fefedd490 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr @@ -0,0 +1,26 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6 + | +LL | impl foreign::Trait0 for <() as Trait>::Assoc {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9 + | +LL | impl foreign::Trait0 for <() as Trait>::Assoc {} + | ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning: 2 warnings emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr new file mode 100644 index 0000000000000..8964fefedd490 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr @@ -0,0 +1,26 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6 + | +LL | impl foreign::Trait0 for <() as Trait>::Assoc {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9 + | +LL | impl foreign::Trait0 for <() as Trait>::Assoc {} + | ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning: 2 warnings emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.rs b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.rs new file mode 100644 index 0000000000000..c5340e854054d --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.rs @@ -0,0 +1,24 @@ +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ check-pass +//@ compile-flags: --crate-type=lib +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +trait Trait { type Assoc; } + +impl Trait for () { + type Assoc = LocalTy; +} + +struct LocalTy; + +impl foreign::Trait0 for <() as Trait>::Assoc {} +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler +//~| WARNING type parameter `U` must be covered by another type +//~| WARNING this was previously accepted by the compiler + + +fn main() {} diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr new file mode 100644 index 0000000000000..28b8c3f4a94bc --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr @@ -0,0 +1,37 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:22:6 + | +LL | impl foreign::Trait0 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:27:6 + | +LL | impl foreign::Trait0<::Output, Local, T> for Option {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:40:6 + | +LL | impl foreign::Trait1 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning: 3 warnings emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr new file mode 100644 index 0000000000000..28b8c3f4a94bc --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr @@ -0,0 +1,37 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:22:6 + | +LL | impl foreign::Trait0 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:27:6 + | +LL | impl foreign::Trait0<::Output, Local, T> for Option {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-projections-not-covering.rs:40:6 + | +LL | impl foreign::Trait1 for ::Output {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +warning: 3 warnings emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.rs b/tests/ui/coherence/orphan-check-projections-not-covering.rs new file mode 100644 index 0000000000000..8c2a9a17e2b84 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-not-covering.rs @@ -0,0 +1,42 @@ +// Regression test for issue #99554. +// Projections might not cover type parameters. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ check-pass +//@ compile-flags: --crate-type=lib +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +trait Identity { + type Output; +} + +impl Identity for T { + type Output = T; +} + +struct Local; + +impl foreign::Trait0 for ::Output {} +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler + + +impl foreign::Trait0<::Output, Local, T> for Option {} +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler + +pub trait Deferred { + type Output; +} + +// A downstream user could implement +// +// impl Deferred for Type { type Output = T; } +// struct Type(T); +// +impl foreign::Trait1 for ::Output {} +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr new file mode 100644 index 0000000000000..0346a9d665cf5 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-unsat-bounds.rs:28:6 + | +LL | impl foreign::Trait1 for as Discard>::Output + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr new file mode 100644 index 0000000000000..0346a9d665cf5 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + --> $DIR/orphan-check-projections-unsat-bounds.rs:28:6 + | +LL | impl foreign::Trait1 for as Discard>::Output + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`) + | + = 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 #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.rs b/tests/ui/coherence/orphan-check-projections-unsat-bounds.rs new file mode 100644 index 0000000000000..bc52673a016f4 --- /dev/null +++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.rs @@ -0,0 +1,35 @@ +// This used to ICE in an earlier iteration of #117164. +// The normalization performed during orphan checking happens inside an empty ParamEnv and +// with type parameters mapped to fresh infer vars. Therefore it may fail for example due to +// unsatisfied bounds while normalization outside of orphan checking succeeds. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ check-pass +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +struct Wrapper(T); + +trait Bound {} + +trait Discard { type Output; } + +impl Discard for Wrapper +where + Wrapper: Bound +{ + type Output = LocalTy; +} + +struct LocalTy; + +impl foreign::Trait1 for as Discard>::Output +//~^ WARNING type parameter `T` must be covered by another type +//~| WARNING this was previously accepted by the compiler +where + Wrapper: Bound +{} + +fn main() {} diff --git a/tests/ui/coherence/orphan-check-weak-aliases-covering.rs b/tests/ui/coherence/orphan-check-weak-aliases-covering.rs new file mode 100644 index 0000000000000..a8b9e905c70b5 --- /dev/null +++ b/tests/ui/coherence/orphan-check-weak-aliases-covering.rs @@ -0,0 +1,20 @@ +// Weak aliases cover type parameters if they normalize to a (local) type that covers them. + +//@ check-pass +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Alias = LocalWrapper; + +struct Local; +struct LocalWrapper(T); + +impl foreign::Trait1 for Alias {} + +fn main() {} diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.classic.stderr new file mode 100644 index 0000000000000..276833fa17122 --- /dev/null +++ b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.classic.stderr @@ -0,0 +1,12 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6 + | +LL | impl foreign::Trait1 for Identity {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr new file mode 100644 index 0000000000000..276833fa17122 --- /dev/null +++ b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.next.stderr @@ -0,0 +1,12 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6 + | +LL | impl foreign::Trait1 for Identity {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs new file mode 100644 index 0000000000000..9ebc45a882937 --- /dev/null +++ b/tests/ui/coherence/orphan-check-weak-aliases-not-covering.rs @@ -0,0 +1,19 @@ +// Weak aliases might not cover type parameters. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Identity = T; + +struct Local; + +impl foreign::Trait1 for Identity {} +//~^ ERROR type parameter `T` must be covered by another type + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs new file mode 100644 index 0000000000000..05bd0d91168a3 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs @@ -0,0 +1,13 @@ +//@ edition:2021 +// issues rust-lang/rust#111911 +// test for ICE opaque type with non-universal region substs + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +pub async fn foo() {} +//~^ ERROR const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias +//~| ERROR const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias +fn bar() -> impl Sized {} + +pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr new file mode 100644 index 0000000000000..1bdb9cd9501a7 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr @@ -0,0 +1,16 @@ +error: const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/opaque_type_with_non-universal_region_substs_ice-111911.rs:8:43 + | +LL | pub async fn foo() {} + | ^^ + +error: const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/opaque_type_with_non-universal_region_substs_ice-111911.rs:8:43 + | +LL | pub async fn foo() {} + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs new file mode 100644 index 0000000000000..68b8b48981680 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs @@ -0,0 +1,32 @@ +// ICE Inconsistent rustc_transmute::is_transmutable(...) result, got Yes +// issue: rust-lang/rust#110969 +#![feature(adt_const_params, generic_const_exprs, transmutability)] +#![allow(incomplete_features, unstable_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom, + //~^ ERROR trait takes at most 2 generic arguments but 3 generic arguments were supplied + { + } +} + +fn via_associated_const() { + struct Context; + #[repr(C)] + struct Src; + #[repr(C)] + struct Dst; + + trait Trait { + const FALSE: bool = assert::is_transmutable::(); + //~^ ERROR mismatched types + //~| ERROR `Src` cannot be safely transmuted into `Dst` + //~| ERROR mismatched types + } +} + +pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr new file mode 100644 index 0000000000000..1dbacaee3c2d8 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr @@ -0,0 +1,39 @@ +error[E0107]: trait takes at most 2 generic arguments but 3 generic arguments were supplied + --> $DIR/transmutable-ice-110969.rs:11:14 + | +LL | Dst: BikeshedIntrinsicFrom, + | ^^^^^^^^^^^^^^^^^^^^^ ------ help: remove this generic argument + | | + | expected at most 2 generic arguments + +error[E0308]: mismatched types + --> $DIR/transmutable-ice-110969.rs:25:74 + | +LL | const FALSE: bool = assert::is_transmutable::(); + | ^^ expected `Assume`, found `()` + +error[E0277]: `Src` cannot be safely transmuted into `Dst` + --> $DIR/transmutable-ice-110969.rs:25:60 + | +LL | const FALSE: bool = assert::is_transmutable::(); + | ^^^ `Dst` may carry safety invariants + | +note: required by a bound in `is_transmutable` + --> $DIR/transmutable-ice-110969.rs:11:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0308]: mismatched types + --> $DIR/transmutable-ice-110969.rs:25:29 + | +LL | const FALSE: bool = assert::is_transmutable::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0277, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs index 7332a8f03c05f..f1305202ad452 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, generic_const_exprs)] +#![feature(generic_const_exprs)] //~^ WARN the feature `generic_const_exprs` is incomplete fn foo() { diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr index a85e0cbcf7e99..03b0004bf0bdb 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -1,8 +1,8 @@ warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-block-is-poly.rs:1:26 + --> $DIR/const-block-is-poly.rs:1:12 | -LL | #![feature(inline_const, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs index 4333ec9f5522d..f9cf8210d6512 100644 --- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(inline_const, generic_const_exprs)] +#![feature(generic_const_exprs)] #![allow(incomplete_features)] use std::marker::PhantomData; diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs new file mode 100644 index 0000000000000..4bea3ad87f5ed --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs @@ -0,0 +1,23 @@ +// issue: rust-lang/rust#113776 +// ice: expected type of closure body to be a closure or coroutine +//@ edition: 2021 +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +use core::ops::SubAssign; + +fn f( + data: &[(); { + let f: F = async { 1 }; + //~^ ERROR cannot find type `F` in this scope + + 1 + }], +) -> impl Iterator { +//~^ ERROR the type parameter `Rhs` must be explicitly specified +//~| ERROR `()` is not an iterator +//~| ERROR trait objects must include the `dyn` keyword +//~| ERROR the type parameter `Rhs` must be explicitly specified [E0393] +} + +pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr new file mode 100644 index 0000000000000..be79450a3ce31 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr @@ -0,0 +1,68 @@ +error[E0412]: cannot find type `F` in this scope + --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:11:17 + | +LL | let f: F = async { 1 }; + | ^ + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + | + = note: similarly named trait `Fn` defined here + | +help: a trait with a similar name exists + | +LL | let f: Fn = async { 1 }; + | ~~ +help: you might be missing a type parameter + | +LL | fn f( + | +++ + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 + | +LL | ) -> impl Iterator { + | ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign` + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | + = note: type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 + | +LL | ) -> impl Iterator { + | ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign` + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | + = note: type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: `()` is not an iterator + --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:6 + | +LL | ) -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator + | + = help: the trait `Iterator` is not implemented for `()` + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 + | +LL | ) -> impl Iterator { + | ^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | ) -> impl Iterator { + | +++ +help: you might have meant to write a bound here + | +LL | ) -> impl Iterator { + | ~ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0393, E0412, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/generic_const_exprs/failed-to-resolve-instance-ice-111667.rs b/tests/ui/const-generics/generic_const_exprs/failed-to-resolve-instance-ice-111667.rs new file mode 100644 index 0000000000000..c547b54e16b01 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/failed-to-resolve-instance-ice-111667.rs @@ -0,0 +1,18 @@ +// issue rust-lang/rust#111667 +// ICE failed to resolve instance for <[f32; 2] as CrossProduct .. +//@ check-pass + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +pub trait CrossProduct<'a, T, R> { + fn cross(&'a self, t: &'a T) -> R; +} + +impl<'a, T, U, const N: usize> CrossProduct<'a, [U; N], [(&'a T, &'a U); N * N]> for [T; N] { + fn cross(&'a self, us: &'a [U; N]) -> [(&'a T, &'a U); N * N] { + std::array::from_fn(|i| (&self[i / N], &us[i % N])) + } +} + +pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs b/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs index 3bc02f4c6bbfb..073e0fe0a7fdb 100644 --- a/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs +++ b/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(generic_const_exprs)] -#![feature(inline_const)] #![allow(incomplete_features)] pub struct ConstDefaultUnstable; diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr index 92dedd74feb50..941764a575e6b 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -29,6 +29,11 @@ error[E0229]: associated type bindings are not allowed here | LL | impl Foo for Bar { | ^^^^^ associated type not allowed here + | +help: to use `3` as a generic argument specify it directly + | +LL | impl Foo<3> for Bar { + | ~ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr index 801d14b395054..a4c9e065c15ca 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -41,6 +41,11 @@ error[E0229]: associated type bindings are not allowed here | LL | impl Foo for Bar { | ^^^^^^^^^^^ associated type not allowed here + | +help: to use `3` as a generic argument specify it directly + | +LL | impl Foo<3> for Bar { + | ~ error: aborting due to 4 previous errors diff --git a/tests/ui/const_prop/dont-propagate-generic-instance-2.rs b/tests/ui/const_prop/dont-propagate-generic-instance-2.rs index 768c9b3171a82..08064bc658991 100644 --- a/tests/ui/const_prop/dont-propagate-generic-instance-2.rs +++ b/tests/ui/const_prop/dont-propagate-generic-instance-2.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - // Makes sure we don't propagate generic instances of `Self: ?Sized` blanket impls. // This is relevant when we have an overlapping impl and builtin dyn instance. // See for more context. diff --git a/tests/ui/consts/closure-structural-match-issue-90013.rs b/tests/ui/consts/closure-structural-match-issue-90013.rs index 7a5d9b69ee4a0..454341a77843e 100644 --- a/tests/ui/consts/closure-structural-match-issue-90013.rs +++ b/tests/ui/consts/closure-structural-match-issue-90013.rs @@ -1,6 +1,5 @@ // Regression test for issue 90013. //@ check-pass -#![feature(inline_const)] fn main() { const { || {} }; diff --git a/tests/ui/consts/const-block-const-bound.rs b/tests/ui/consts/const-block-const-bound.rs index b0d5e19ad5541..933eb6cfc0afb 100644 --- a/tests/ui/consts/const-block-const-bound.rs +++ b/tests/ui/consts/const-block-const-bound.rs @@ -1,7 +1,7 @@ //@ known-bug: #103507 #![allow(unused)] -#![feature(const_trait_impl, inline_const, negative_impls)] +#![feature(const_trait_impl, negative_impls)] use std::marker::Destruct; diff --git a/tests/ui/consts/const-blocks/fn-call-in-const.rs b/tests/ui/consts/const-blocks/fn-call-in-const.rs index 9bf267b7de9aa..a3e24ddae7d1e 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-const.rs +++ b/tests/ui/consts/const-blocks/fn-call-in-const.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(inline_const)] #![allow(unused)] // Some type that is not copyable. diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.rs b/tests/ui/consts/const-eval/const_fn_target_feature.rs index b56b68a579583..ee669abb51e59 100644 --- a/tests/ui/consts/const-eval/const_fn_target_feature.rs +++ b/tests/ui/consts/const-eval/const_fn_target_feature.rs @@ -1,5 +1,6 @@ //@ only-x86_64 -//@ compile-flags:-C target-feature=+ssse3 +// Set the base cpu explicitly, in case the default has been changed. +//@ compile-flags: -C target-cpu=x86-64 -C target-feature=+ssse3 #![crate_type = "lib"] diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr index 0c7c69b794aa9..d3a00b57ebb50 100644 --- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr +++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_fn_target_feature.rs:10:24 + --> $DIR/const_fn_target_feature.rs:11:24 | LL | const B: () = unsafe { avx2_fn() }; | ^^^^^^^^^ calling a function that requires unavailable target features: avx2 diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs index 6c4fca3562607..2517560c2c34c 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(inline_const)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs index 146a87862e8c7..c53bb36f4a2ce 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(inline_const)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/ice-unhandled-type-122191.rs b/tests/ui/consts/const-eval/ice-unhandled-type-122191.rs new file mode 100644 index 0000000000000..a92b99976e262 --- /dev/null +++ b/tests/ui/consts/const-eval/ice-unhandled-type-122191.rs @@ -0,0 +1,18 @@ +type Foo = impl Send; +//~^ ERROR `impl Trait` in type aliases is unstable + +struct A; + +const VALUE: Foo = value(); +//~^ ERROR cannot find function `value` in this scope + +fn test() { + match VALUE { + 0 | 0 => {} +//~^ ERROR mismatched types +//~| ERROR mismatched types + _ => (), + } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr b/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr new file mode 100644 index 0000000000000..daf0ccaa776ca --- /dev/null +++ b/tests/ui/consts/const-eval/ice-unhandled-type-122191.stderr @@ -0,0 +1,58 @@ +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/ice-unhandled-type-122191.rs:1:12 + | +LL | type Foo = impl Send; + | ^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0425]: cannot find function `value` in this scope + --> $DIR/ice-unhandled-type-122191.rs:6:20 + | +LL | const VALUE: Foo = value(); + | ^^^^^ not found in this scope + +error[E0308]: mismatched types + --> $DIR/ice-unhandled-type-122191.rs:11:9 + | +LL | type Foo = impl Send; + | --------- the expected opaque type +... +LL | match VALUE { + | ----- this expression has type `Foo` +LL | 0 | 0 => {} + | ^ expected opaque type, found integer + | + = note: expected opaque type `Foo` + found type `{integer}` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/ice-unhandled-type-122191.rs:9:4 + | +LL | fn test() { + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/ice-unhandled-type-122191.rs:11:13 + | +LL | type Foo = impl Send; + | --------- the expected opaque type +... +LL | match VALUE { + | ----- this expression has type `Foo` +LL | 0 | 0 => {} + | ^ expected opaque type, found integer + | + = note: expected opaque type `Foo` + found type `{integer}` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/ice-unhandled-type-122191.rs:9:4 + | +LL | fn test() { + | ^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0425, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-eval/promoted_errors.noopt.stderr b/tests/ui/consts/const-eval/promoted_errors.noopt.stderr deleted file mode 100644 index 2a254bfde8204..0000000000000 --- a/tests/ui/consts/const-eval/promoted_errors.noopt.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:15:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:9 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:19:5 - | -LL | 1 / 0 - | ^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:30 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:23:5 - | -LL | 1 / (1 - 1) - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:27:5 - | -LL | 1 / (false as i32) - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:31:5 - | -LL | [1, 2, 3][4] - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 - -warning: 5 warnings emitted - diff --git a/tests/ui/consts/const-eval/promoted_errors.opt.stderr b/tests/ui/consts/const-eval/promoted_errors.opt.stderr deleted file mode 100644 index 2a254bfde8204..0000000000000 --- a/tests/ui/consts/const-eval/promoted_errors.opt.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:15:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:9 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:19:5 - | -LL | 1 / 0 - | ^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:30 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:23:5 - | -LL | 1 / (1 - 1) - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:27:5 - | -LL | 1 / (false as i32) - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:31:5 - | -LL | [1, 2, 3][4] - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 - -warning: 5 warnings emitted - diff --git a/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr deleted file mode 100644 index 2a254bfde8204..0000000000000 --- a/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ /dev/null @@ -1,44 +0,0 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:15:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:9 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:19:5 - | -LL | 1 / 0 - | ^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:11:30 - | -LL | #![warn(arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:23:5 - | -LL | 1 / (1 - 1) - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:27:5 - | -LL | 1 / (false as i32) - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:31:5 - | -LL | [1, 2, 3][4] - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 - -warning: 5 warnings emitted - diff --git a/tests/ui/consts/const-eval/promoted_errors.rs b/tests/ui/consts/const-eval/promoted_errors.rs deleted file mode 100644 index e806d4a32468d..0000000000000 --- a/tests/ui/consts/const-eval/promoted_errors.rs +++ /dev/null @@ -1,52 +0,0 @@ -//@ revisions: noopt opt opt_with_overflow_checks -//@[noopt]compile-flags: -C opt-level=0 -//@[opt]compile-flags: -O -//@[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O - -//@ build-pass -//@ ignore-pass (test emits codegen-time warnings and verifies that they are not errors) - -//! This test ensures that when we promote code that fails to evaluate, the build still succeeds. - -#![warn(arithmetic_overflow, unconditional_panic)] - -// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. -const fn overflow() -> u32 { - 0 - 1 - //~^ WARN this arithmetic operation will overflow -} -const fn div_by_zero1() -> i32 { - 1 / 0 - //~^ WARN this operation will panic at runtime -} -const fn div_by_zero2() -> i32 { - 1 / (1 - 1) - //~^ WARN this operation will panic at runtime -} -const fn div_by_zero3() -> i32 { - 1 / (false as i32) - //~^ WARN this operation will panic at runtime -} -const fn oob() -> i32 { - [1, 2, 3][4] - //~^ WARN this operation will panic at runtime -} - -const fn mk_false() -> bool { false } - -// An actually used constant referencing failing promoteds in dead code. -// This needs to always work. -const Y: () = { - if mk_false() { - let _x: &'static u32 = &overflow(); - let _x: &'static i32 = &div_by_zero1(); - let _x: &'static i32 = &div_by_zero2(); - let _x: &'static i32 = &div_by_zero3(); - let _x: &'static i32 = &oob(); - } - () -}; - -fn main() { - Y; -} diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index e5dfd5ca29397..2fbf135c9975c 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -3,7 +3,7 @@ // ignore-tidy-linelength //@ normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼" -> "╾ALLOC_ID$1╼" #![allow(invalid_value)] -#![feature(generic_nonzero, never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] +#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] use std::mem; use std::alloc::Layout; diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index 76bd5248ffd89..10d304436f807 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -2,7 +2,7 @@ //@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" #![allow(invalid_value)] // make sure we cannot allow away the errors tested here -#![feature(generic_nonzero, rustc_attrs, ptr_metadata)] +#![feature(rustc_attrs, ptr_metadata)] use std::mem; use std::ptr::NonNull; diff --git a/tests/ui/consts/const-eval/valid-const.rs b/tests/ui/consts/const-eval/valid-const.rs index 15d3e88345658..777484c6b0927 100644 --- a/tests/ui/consts/const-eval/valid-const.rs +++ b/tests/ui/consts/const-eval/valid-const.rs @@ -1,7 +1,6 @@ //@ check-pass // // Some constants that *are* valid -#![feature(generic_nonzero)] use std::mem; use std::ptr::NonNull; diff --git a/tests/ui/consts/issue-102117.rs b/tests/ui/consts/issue-102117.rs index 3ed90aed2350d..6cb9832bcd81b 100644 --- a/tests/ui/consts/issue-102117.rs +++ b/tests/ui/consts/issue-102117.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, const_type_id)] +#![feature(const_type_id)] use std::alloc::Layout; use std::any::TypeId; diff --git a/tests/ui/consts/mono-reachable-invalid-const.rs b/tests/ui/consts/mono-reachable-invalid-const.rs new file mode 100644 index 0000000000000..aabdb071bc9fb --- /dev/null +++ b/tests/ui/consts/mono-reachable-invalid-const.rs @@ -0,0 +1,23 @@ +//@ build-fail + +struct Bar; + +impl Bar { + const ASSERT: bool = { + let b = std::convert::identity(1); + ["oops"][b]; //~ ERROR evaluation of `Bar::<0>::ASSERT` failed + true + }; + + fn assert() { + let val = Self::ASSERT; + if val { + std::convert::identity(val); + } + } +} + + +fn main() { + Bar::<0>::assert(); +} diff --git a/tests/ui/consts/mono-reachable-invalid-const.stderr b/tests/ui/consts/mono-reachable-invalid-const.stderr new file mode 100644 index 0000000000000..6b7b25b59b821 --- /dev/null +++ b/tests/ui/consts/mono-reachable-invalid-const.stderr @@ -0,0 +1,29 @@ +error[E0080]: evaluation of `Bar::<0>::ASSERT` failed + --> $DIR/mono-reachable-invalid-const.rs:8:9 + | +LL | ["oops"][b]; + | ^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +note: erroneous constant encountered + --> $DIR/mono-reachable-invalid-const.rs:13:19 + | +LL | let val = Self::ASSERT; + | ^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/mono-reachable-invalid-const.rs:13:19 + | +LL | let val = Self::ASSERT; + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: the above error was encountered while instantiating `fn Bar::<0>::assert` + --> $DIR/mono-reachable-invalid-const.rs:22:5 + | +LL | Bar::<0>::assert(); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs index 9b16f32532a77..80912937f3158 100644 --- a/tests/ui/consts/promote-not.rs +++ b/tests/ui/consts/promote-not.rs @@ -51,6 +51,15 @@ const TEST_DROP_NOT_PROMOTE: &String = { }; +// We do not promote function calls in `const` initializers in dead code. +const fn mk_panic() -> u32 { panic!() } +const fn mk_false() -> bool { false } +const Y: () = { + if mk_false() { + let _x: &'static u32 = &mk_panic(); //~ ERROR temporary value dropped while borrowed + } +}; + fn main() { // We must not promote things with interior mutability. Not even if we "project it away". let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index 07d4a135ed43d..d8b6091dc9aab 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -47,6 +47,16 @@ LL | let x = &String::new(); LL | }; | - value is dropped here +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:59:33 + | +LL | let _x: &'static u32 = &mk_panic(); + | ------------ ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:21:32 | @@ -68,7 +78,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:56:29 + --> $DIR/promote-not.rs:65:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -79,7 +89,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:57:29 + --> $DIR/promote-not.rs:66:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -90,7 +100,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:60:29 + --> $DIR/promote-not.rs:69:29 | LL | let _val: &'static _ = &(1/0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -101,7 +111,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:61:29 + --> $DIR/promote-not.rs:70:29 | LL | let _val: &'static _ = &(1/(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -112,7 +122,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:62:29 + --> $DIR/promote-not.rs:71:29 | LL | let _val: &'static _ = &((1+1)/(1-1)); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -123,7 +133,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:63:29 + --> $DIR/promote-not.rs:72:29 | LL | let _val: &'static _ = &(i32::MIN/-1); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -134,7 +144,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:64:29 + --> $DIR/promote-not.rs:73:29 | LL | let _val: &'static _ = &(i32::MIN/(0-1)); | ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -145,7 +155,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:29 + --> $DIR/promote-not.rs:74:29 | LL | let _val: &'static _ = &(-128i8/-1); | ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -156,7 +166,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:66:29 + --> $DIR/promote-not.rs:75:29 | LL | let _val: &'static _ = &(1%0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -167,7 +177,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:67:29 + --> $DIR/promote-not.rs:76:29 | LL | let _val: &'static _ = &(1%(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -178,7 +188,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:68:29 + --> $DIR/promote-not.rs:77:29 | LL | let _val: &'static _ = &([1,2,3][4]+1); | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -189,7 +199,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:72:29 + --> $DIR/promote-not.rs:81:29 | LL | let _val: &'static _ = &TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -200,7 +210,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:74:29 + --> $DIR/promote-not.rs:83:29 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -211,7 +221,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:74:30 + --> $DIR/promote-not.rs:83:30 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -222,7 +232,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:77:29 + --> $DIR/promote-not.rs:86:29 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -233,7 +243,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:77:31 + --> $DIR/promote-not.rs:86:31 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -244,7 +254,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:80:29 + --> $DIR/promote-not.rs:89:29 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -255,7 +265,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:80:31 + --> $DIR/promote-not.rs:89:31 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement @@ -264,7 +274,7 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1]; | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:89:26 + --> $DIR/promote-not.rs:98:26 | LL | let x: &'static _ = &UnionWithCell { f1: 0 }; | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -274,7 +284,7 @@ LL | LL | } | - temporary value is freed at the end of this statement -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors Some errors have detailed explanations: E0493, E0716. For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/promotion.rs b/tests/ui/consts/promotion.rs index b18495a4a6bf5..457e807c970b3 100644 --- a/tests/ui/consts/promotion.rs +++ b/tests/ui/consts/promotion.rs @@ -5,28 +5,30 @@ //@ build-pass +#![allow(arithmetic_overflow)] + +use std::mem; + const fn assert_static(_: &'static T) {} -#[allow(unconditional_panic)] -const fn fail() -> i32 { - 1/0 -} -const C: i32 = { - // Promoted that fails to evaluate in dead code -- this must work - // (for backwards compatibility reasons). - if false { - assert_static(&fail()); - } +// Function calls in const on the "main path" (not inside conditionals) +// do get promoted. +const fn make_thing() -> i32 { 42 +} +const C: () = { + assert_static(&make_thing()); + // Make sure this works even when there's other stuff (like function calls) above the relevant + // call in the const initializer. + assert_static(&make_thing()); }; fn main() { assert_static(&["a", "b", "c"]); assert_static(&["d", "e", "f"]); - assert_eq!(C, 42); // make sure that this does not cause trouble despite overflowing - assert_static(&(0-1)); + assert_static(&(0u32 - 1)); // div-by-non-0 (and also not MIN/-1) is okay assert_static(&(1/1)); @@ -36,12 +38,16 @@ fn main() { assert_static(&(1%1)); // in-bounds array access is okay - assert_static(&([1,2,3][0] + 1)); - assert_static(&[[1,2][1]]); + assert_static(&([1, 2, 3][0] + 1)); + assert_static(&[[1, 2][1]]); // Top-level projections are not part of the promoted, so no error here. if false { #[allow(unconditional_panic)] - assert_static(&[1,2,3][4]); + assert_static(&[1, 2, 3][4]); } + + // More complicated case involving control flow and a `#[rustc_promotable]` function + let decision = std::hint::black_box(true); + let x: &'static usize = if decision { &mem::size_of::() } else { &0 }; } diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr new file mode 100644 index 0000000000000..a50c49d536251 --- /dev/null +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr @@ -0,0 +1,23 @@ +error[E0080]: evaluation of `Fail::::C` failed + --> $DIR/collect-in-promoted-const.rs:9:19 + | +LL | const C: () = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant encountered + --> $DIR/collect-in-promoted-const.rs:20:21 + | +LL | let _val = &Fail::::C; + | ^^^^^^^^^^^^ + +note: the above error was encountered while instantiating `fn f::` + --> $DIR/collect-in-promoted-const.rs:25:5 + | +LL | f::(); + | ^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr new file mode 100644 index 0000000000000..cf0aa8ef7a73d --- /dev/null +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr @@ -0,0 +1,39 @@ +error[E0080]: evaluation of `Fail::::C` failed + --> $DIR/collect-in-promoted-const.rs:9:19 + | +LL | const C: () = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant encountered + --> $DIR/collect-in-promoted-const.rs:20:21 + | +LL | let _val = &Fail::::C; + | ^^^^^^^^^^^^ + +error[E0080]: evaluation of `Fail::::C` failed + --> $DIR/collect-in-promoted-const.rs:9:19 + | +LL | const C: () = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant encountered + --> $DIR/collect-in-promoted-const.rs:20:21 + | +LL | let _val = &Fail::::C; + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: the above error was encountered while instantiating `fn f::` + --> $DIR/collect-in-promoted-const.rs:25:5 + | +LL | f::(); + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs new file mode 100644 index 0000000000000..4a3ce92e8f90d --- /dev/null +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs @@ -0,0 +1,26 @@ +//@revisions: noopt opt +//@ build-fail +//@[noopt] compile-flags: -Copt-level=0 +//@[opt] compile-flags: -O +//! Make sure we error on erroneous consts even if they get promoted. + +struct Fail(T); +impl Fail { + const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + //[opt]~^ ERROR evaluation of `Fail::::C` failed + // (Not sure why optimizations lead to this being emitted twice, but as long as compilation + // fails either way it's fine.) +} + +#[inline(never)] +fn f() { + if false { + // If promotion moved `C` from our required_consts to its own, without adding itself to + // our required_consts, then we'd miss the const-eval failure here. + let _val = &Fail::::C; + } +} + +fn main() { + f::(); +} diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs index 187494180ad1d..48caece6ff56f 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.rs +++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs @@ -1,7 +1,7 @@ //@revisions: noopt opt //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O -//! Make sure we error on erroneous consts even if they are unused. +//! Make sure we evaluate const fn calls even if they get promoted and their result ignored. const unsafe fn ub() { std::hint::unreachable_unchecked(); diff --git a/tests/ui/consts/tuple-struct-constructors.rs b/tests/ui/consts/tuple-struct-constructors.rs index d2f25aeec9b17..e645b57407507 100644 --- a/tests/ui/consts/tuple-struct-constructors.rs +++ b/tests/ui/consts/tuple-struct-constructors.rs @@ -1,7 +1,6 @@ //@ run-pass // // https://github.com/rust-lang/rust/issues/41898 -#![feature(generic_nonzero)] use std::num::NonZero; diff --git a/tests/ui/coroutine/addassign-yield.rs b/tests/ui/coroutine/addassign-yield.rs index 8718e73512f71..8329b53d715e6 100644 --- a/tests/ui/coroutine/addassign-yield.rs +++ b/tests/ui/coroutine/addassign-yield.rs @@ -5,21 +5,21 @@ // is being used), we were failing to account for all types that might // possibly be live across a yield point. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo() { - let _x = static || { + let _x = #[coroutine] static || { let mut s = String::new(); s += { yield; "" }; }; - let _y = static || { + let _y = #[coroutine] static || { let x = &mut 0; *{ yield; x } += match String::new() { _ => 0 }; }; // Please don't ever actually write something like this - let _z = static || { + let _z = #[coroutine] static || { let x = &mut 0; *{ let inner = &mut 1; diff --git a/tests/ui/coroutine/auto-trait-regions.rs b/tests/ui/coroutine/auto-trait-regions.rs index 5fce70e8e54d2..4c239f9ee76cf 100644 --- a/tests/ui/coroutine/auto-trait-regions.rs +++ b/tests/ui/coroutine/auto-trait-regions.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(auto_traits)] #![feature(negative_impls)] @@ -23,7 +23,7 @@ fn assert_foo(f: T) {} fn main() { // Make sure 'static is erased for coroutine interiors so we can't match it in trait selection let x: &'static _ = &OnlyFooIfStaticRef(No); - let gen = move || { + let gen = #[coroutine] move || { let x = x; yield; assert_foo(x); @@ -33,7 +33,7 @@ fn main() { // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); - let gen = move || { + let gen = #[coroutine] move || { let x = x; yield; assert_foo(x); @@ -41,7 +41,7 @@ fn main() { assert_foo(gen); // ok // Disallow impls which relates lifetimes in the coroutine interior - let gen = move || { + let gen = #[coroutine] move || { let a = A(&mut true, &mut true, No); //~^ temporary value dropped while borrowed //~| temporary value dropped while borrowed diff --git a/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs b/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs index 8af6973134a67..8ecb8c0c09793 100644 --- a/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs +++ b/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs @@ -5,6 +5,7 @@ use std::marker::Unpin; use std::ops::Coroutine; pub fn g() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { yield; } diff --git a/tests/ui/coroutine/auxiliary/unwind-aux.rs b/tests/ui/coroutine/auxiliary/unwind-aux.rs index ff1e8ed32cd49..5d5e5c2218d39 100644 --- a/tests/ui/coroutine/auxiliary/unwind-aux.rs +++ b/tests/ui/coroutine/auxiliary/unwind-aux.rs @@ -2,9 +2,10 @@ //@ no-prefer-dynamic //@ edition:2021 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] pub fn run(a: T) { - let _ = move || { + let _ = #[coroutine] + move || { drop(a); yield; }; diff --git a/tests/ui/coroutine/auxiliary/xcrate-reachable.rs b/tests/ui/coroutine/auxiliary/xcrate-reachable.rs index 673153f0619ea..0b5d18823004a 100644 --- a/tests/ui/coroutine/auxiliary/xcrate-reachable.rs +++ b/tests/ui/coroutine/auxiliary/xcrate-reachable.rs @@ -7,6 +7,7 @@ fn msg() -> u32 { } pub fn foo() -> impl Coroutine<(), Yield = (), Return = u32> { + #[coroutine] || { yield; return msg(); diff --git a/tests/ui/coroutine/auxiliary/xcrate.rs b/tests/ui/coroutine/auxiliary/xcrate.rs index f749a95ad35a3..52f188135bd1b 100644 --- a/tests/ui/coroutine/auxiliary/xcrate.rs +++ b/tests/ui/coroutine/auxiliary/xcrate.rs @@ -1,9 +1,10 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::marker::Unpin; use std::ops::Coroutine; pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { if false { yield; @@ -12,7 +13,10 @@ pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> { } pub fn bar(t: T) -> Box + Unpin> { - Box::new(|| { - yield t; - }) + Box::new( + #[coroutine] + || { + yield t; + }, + ) } diff --git a/tests/ui/coroutine/borrow-in-tail-expr.rs b/tests/ui/coroutine/borrow-in-tail-expr.rs index 2f0aa62019e83..380e95cfc7765 100644 --- a/tests/ui/coroutine/borrow-in-tail-expr.rs +++ b/tests/ui/coroutine/borrow-in-tail-expr.rs @@ -1,9 +1,9 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _a = || { + let _a = #[coroutine] || { yield; let a = String::new(); a.len() diff --git a/tests/ui/coroutine/borrowing.rs b/tests/ui/coroutine/borrowing.rs index 778eed8bd0d9f..a6628766c1bad 100644 --- a/tests/ui/coroutine/borrowing.rs +++ b/tests/ui/coroutine/borrowing.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -6,13 +6,13 @@ use std::pin::Pin; fn main() { let _b = { let a = 3; - Pin::new(&mut || yield &a).resume(()) + Pin::new(&mut #[coroutine] || yield &a).resume(()) //~^ ERROR: `a` does not live long enough }; let _b = { let a = 3; - || { + #[coroutine] || { yield &a //~^ ERROR: `a` does not live long enough } diff --git a/tests/ui/coroutine/borrowing.stderr b/tests/ui/coroutine/borrowing.stderr index acd4cdafdfdf7..4f8b97377777a 100644 --- a/tests/ui/coroutine/borrowing.stderr +++ b/tests/ui/coroutine/borrowing.stderr @@ -1,13 +1,14 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:9:33 + --> $DIR/borrowing.rs:9:46 | LL | let _b = { | -- borrow later stored here LL | let a = 3; -LL | Pin::new(&mut || yield &a).resume(()) - | -- ^ borrowed value does not live long enough - | | - | value captured here by coroutine + | - binding `a` declared here +LL | Pin::new(&mut #[coroutine] || yield &a).resume(()) + | -- ^ borrowed value does not live long enough + | | + | value captured here by coroutine LL | LL | }; | - `a` dropped here while still borrowed @@ -18,8 +19,9 @@ error[E0597]: `a` does not live long enough LL | let _b = { | -- borrow later stored here LL | let a = 3; -LL | || { - | -- value captured here by coroutine + | - binding `a` declared here +LL | #[coroutine] || { + | -- value captured here by coroutine LL | yield &a | ^ borrowed value does not live long enough ... diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs b/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs index a316c50e86732..327756ebe6604 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs +++ b/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs @@ -7,27 +7,27 @@ struct Contravariant<'a>(fn(&'a ())); struct Covariant<'a>(fn() -> &'a ()); fn bad1<'short, 'long: 'short>() -> impl Coroutine> { - |_: Covariant<'short>| { + #[coroutine] |_: Covariant<'short>| { let a: Covariant<'long> = yield (); //~^ ERROR lifetime may not live long enough } } fn bad2<'short, 'long: 'short>() -> impl Coroutine> { - |_: Contravariant<'long>| { + #[coroutine] |_: Contravariant<'long>| { let a: Contravariant<'short> = yield (); //~^ ERROR lifetime may not live long enough } } fn good1<'short, 'long: 'short>() -> impl Coroutine> { - |_: Covariant<'long>| { + #[coroutine] |_: Covariant<'long>| { let a: Covariant<'short> = yield (); } } fn good2<'short, 'long: 'short>() -> impl Coroutine> { - |_: Contravariant<'short>| { + #[coroutine] |_: Contravariant<'short>| { let a: Contravariant<'long> = yield (); } } diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr b/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr index e0cbca2dd5267..8eb7ab3501b35 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr +++ b/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr @@ -5,15 +5,15 @@ LL | fn bad1<'short, 'long: 'short>() -> impl Coroutine> { | ------ ----- lifetime `'long` defined here | | | lifetime `'short` defined here -LL | |_: Covariant<'short>| { +LL | #[coroutine] |_: Covariant<'short>| { LL | let a: Covariant<'long> = yield (); | ^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` help: consider adding 'move' keyword before the nested closure | -LL | move |_: Covariant<'short>| { - | ++++ +LL | #[coroutine] move |_: Covariant<'short>| { + | ++++ error: lifetime may not live long enough --> $DIR/check-resume-ty-lifetimes-2.rs:18:40 @@ -22,15 +22,15 @@ LL | fn bad2<'short, 'long: 'short>() -> impl Coroutine> { | ------ ----- lifetime `'long` defined here | | | lifetime `'short` defined here -LL | |_: Contravariant<'long>| { +LL | #[coroutine] |_: Contravariant<'long>| { LL | let a: Contravariant<'short> = yield (); | ^^^^^^^^ yielding this value requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` help: consider adding 'move' keyword before the nested closure | -LL | move |_: Contravariant<'long>| { - | ++++ +LL | #[coroutine] move |_: Contravariant<'long>| { + | ++++ error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes.rs b/tests/ui/coroutine/check-resume-ty-lifetimes.rs index add0b5080a8a8..b75e46c541cc5 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes.rs +++ b/tests/ui/coroutine/check-resume-ty-lifetimes.rs @@ -1,5 +1,5 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(unused)] use std::ops::Coroutine; @@ -9,11 +9,14 @@ use std::pin::pin; fn mk_static(s: &str) -> &'static str { let mut storage: Option<&'static str> = None; - let mut coroutine = pin!(|_: &str| { - let x: &'static str = yield (); - //~^ ERROR lifetime may not live long enough - storage = Some(x); - }); + let mut coroutine = pin!( + #[coroutine] + |_: &str| { + let x: &'static str = yield (); + //~^ ERROR lifetime may not live long enough + storage = Some(x); + } + ); coroutine.as_mut().resume(s); coroutine.as_mut().resume(s); diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes.stderr b/tests/ui/coroutine/check-resume-ty-lifetimes.stderr index f373aa778a82c..1fbaeb9f7fa41 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes.stderr +++ b/tests/ui/coroutine/check-resume-ty-lifetimes.stderr @@ -1,11 +1,11 @@ error: lifetime may not live long enough - --> $DIR/check-resume-ty-lifetimes.rs:13:16 + --> $DIR/check-resume-ty-lifetimes.rs:15:20 | LL | fn mk_static(s: &str) -> &'static str { | - let's call the lifetime of this reference `'1` ... -LL | let x: &'static str = yield (); - | ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` +LL | let x: &'static str = yield (); + | ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/clone-impl-static.rs b/tests/ui/coroutine/clone-impl-static.rs index 9a165cf4672e6..56d1ccac70350 100644 --- a/tests/ui/coroutine/clone-impl-static.rs +++ b/tests/ui/coroutine/clone-impl-static.rs @@ -1,10 +1,11 @@ // gate-test-coroutine_clone // Verifies that static coroutines cannot be cloned/copied. -#![feature(coroutines, coroutine_clone)] +#![feature(coroutines, coroutine_clone, stmt_expr_attributes)] fn main() { - let gen = static move || { + let gen = #[coroutine] + static move || { yield; }; check_copy(&gen); diff --git a/tests/ui/coroutine/clone-impl-static.stderr b/tests/ui/coroutine/clone-impl-static.stderr index 8fa9fb12bf685..43920326d5dfd 100644 --- a/tests/ui/coroutine/clone-impl-static.stderr +++ b/tests/ui/coroutine/clone-impl-static.stderr @@ -1,27 +1,27 @@ -error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Copy` is not satisfied - --> $DIR/clone-impl-static.rs:10:16 +error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Copy` is not satisfied + --> $DIR/clone-impl-static.rs:11:16 | LL | check_copy(&gen); - | ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` + | ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}` | | | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-static.rs:16:18 + --> $DIR/clone-impl-static.rs:17:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Clone` is not satisfied - --> $DIR/clone-impl-static.rs:12:17 +error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Clone` is not satisfied + --> $DIR/clone-impl-static.rs:13:17 | LL | check_clone(&gen); - | ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` + | ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}` | | | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-static.rs:17:19 + --> $DIR/clone-impl-static.rs:18:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index eed6f851bd028..94420e56a2261 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -2,23 +2,25 @@ // Verifies that non-static coroutines can be cloned/copied if all their upvars and locals held // across awaits can be cloned/copied. -#![feature(coroutines, coroutine_clone)] +#![feature(coroutines, coroutine_clone, stmt_expr_attributes)] struct NonClone; -fn main() { +fn test1() { let copyable: u32 = 123; - let clonable_0: Vec = Vec::new(); - let clonable_1: Vec = Vec::new(); - let non_clonable: NonClone = NonClone; - - let gen_copy_0 = move || { + let gen_copy_0 = #[coroutine] + move || { yield; drop(copyable); }; check_copy(&gen_copy_0); check_clone(&gen_copy_0); - let gen_copy_1 = move || { +} + +fn test2() { + let copyable: u32 = 123; + let gen_copy_1 = #[coroutine] + move || { /* let v = vec!['a']; let n = NonClone; @@ -33,7 +35,12 @@ fn main() { }; check_copy(&gen_copy_1); check_clone(&gen_copy_1); - let gen_clone_0 = move || { +} + +fn test3() { + let clonable_0: Vec = Vec::new(); + let gen_clone_0 = #[coroutine] + move || { let v = vec!['a']; yield; drop(v); @@ -43,7 +50,12 @@ fn main() { //~^ ERROR the trait bound `Vec: Copy` is not satisfied //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_0); - let gen_clone_1 = move || { +} + +fn test4() { + let clonable_1: Vec = Vec::new(); + let gen_clone_1 = #[coroutine] + move || { let v = vec!['a']; /* let n = NonClone; @@ -59,7 +71,12 @@ fn main() { //~^ ERROR the trait bound `Vec: Copy` is not satisfied //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_1); - let gen_non_clone = move || { +} + +fn test5() { + let non_clonable: NonClone = NonClone; + let gen_non_clone = #[coroutine] + move || { yield; drop(non_clonable); }; @@ -71,3 +88,5 @@ fn main() { fn check_copy(_x: &T) {} fn check_clone(_x: &T) {} + +fn main() {} diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index 1d4804501d8bc..5330d3bbd39d5 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,76 +1,76 @@ -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` - --> $DIR/clone-impl.rs:42:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` + --> $DIR/clone-impl.rs:49:5 | -LL | let gen_clone_0 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:40:14 + --> $DIR/clone-impl.rs:47:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:72:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` - --> $DIR/clone-impl.rs:42:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` + --> $DIR/clone-impl.rs:49:5 | -LL | let gen_clone_0 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:36:23: 36:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:38:9 + --> $DIR/clone-impl.rs:45:9 | LL | let v = vec!['a']; | - has type `Vec` which does not implement `Copy` LL | yield; | ^^^^^ yield occurs here, with `v` maybe used later note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:72:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` - --> $DIR/clone-impl.rs:58:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` + --> $DIR/clone-impl.rs:70:5 | -LL | let gen_clone_1 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:56:14 + --> $DIR/clone-impl.rs:68:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:72:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` - --> $DIR/clone-impl.rs:58:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` + --> $DIR/clone-impl.rs:70:5 | -LL | let gen_clone_1 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:46:23: 46:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:52:9 + --> $DIR/clone-impl.rs:64:9 | LL | let v = vec!['a']; | - has type `Vec` which does not implement `Copy` @@ -78,27 +78,27 @@ LL | let v = vec!['a']; LL | yield; | ^^^^^ yield occurs here, with `v` maybe used later note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:72:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` - --> $DIR/clone-impl.rs:66:5 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` + --> $DIR/clone-impl.rs:83:5 | -LL | let gen_non_clone = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:64:14 + --> $DIR/clone-impl.rs:81:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:72:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -108,22 +108,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` - --> $DIR/clone-impl.rs:68:5 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` + --> $DIR/clone-impl.rs:85:5 | -LL | let gen_non_clone = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:62:25: 62:32}: Clone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Clone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:64:14 + --> $DIR/clone-impl.rs:81:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:73:19 + --> $DIR/clone-impl.rs:90:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-rpit.next.stderr b/tests/ui/coroutine/clone-rpit.next.stderr index 41aa2d63af016..c223f1f211ac6 100644 --- a/tests/ui/coroutine/clone-rpit.next.stderr +++ b/tests/ui/coroutine/clone-rpit.next.stderr @@ -5,32 +5,32 @@ LL | pub fn foo<'a, 'b>() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires coroutine witness types for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires promoting constants in MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires building MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires match-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires type-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs index 0df9bf616018f..66569b4f42741 100644 --- a/tests/ui/coroutine/clone-rpit.rs +++ b/tests/ui/coroutine/clone-rpit.rs @@ -11,6 +11,7 @@ // witness types, which we don't know until after borrowck. When we later check // the goal for correctness, we want to be able to bind the `impl Clone` opaque. pub fn foo<'a, 'b>() -> impl Clone { + #[coroutine] move |_: ()| { let () = yield (); } diff --git a/tests/ui/coroutine/conditional-drop.rs b/tests/ui/coroutine/conditional-drop.rs index 65d3a9e701ee4..52e1b561946c7 100644 --- a/tests/ui/coroutine/conditional-drop.rs +++ b/tests/ui/coroutine/conditional-drop.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -29,7 +29,7 @@ fn main() { } fn t1() { - let mut a = || { + let mut a = #[coroutine] || { let b = B; if test() { drop(b); @@ -45,7 +45,7 @@ fn t1() { } fn t2() { - let mut a = || { + let mut a = #[coroutine] || { let b = B; if test2() { drop(b); diff --git a/tests/ui/coroutine/control-flow.rs b/tests/ui/coroutine/control-flow.rs index 9070ba17856c9..f64b6f7388366 100644 --- a/tests/ui/coroutine/control-flow.rs +++ b/tests/ui/coroutine/control-flow.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; @@ -24,25 +24,25 @@ fn finish(mut amt: usize, mut t: T) -> T::Return } fn main() { - finish(1, || yield); - finish(8, || { + finish(1, #[coroutine] || yield); + finish(8, #[coroutine] || { for _ in 0..8 { yield; } }); - finish(1, || { + finish(1, #[coroutine] || { if true { yield; } else { } }); - finish(1, || { + finish(1, #[coroutine] || { if false { } else { yield; } }); - finish(2, || { + finish(2, #[coroutine] || { if { yield; false } { yield; panic!() diff --git a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs new file mode 100644 index 0000000000000..07c13239a2ce2 --- /dev/null +++ b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs @@ -0,0 +1,10 @@ +//@ edition:2021 + +trait X { + fn test() -> Self::Assoc<{ async {} }>; + //~^ ERROR associated type `Assoc` not found for `Self` + //~| ERROR associated type `Assoc` not found for `Self` + +} + +pub fn main() {} diff --git a/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr new file mode 100644 index 0000000000000..864c6556d7990 --- /dev/null +++ b/tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr @@ -0,0 +1,17 @@ +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/coroutine-in-orphaned-anon-const.rs:4:24 + | +LL | fn test() -> Self::Assoc<{ async {} }>; + | ^^^^^ associated type `Assoc` not found + +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/coroutine-in-orphaned-anon-const.rs:4:24 + | +LL | fn test() -> Self::Assoc<{ async {} }>; + | ^^^^^ associated type `Assoc` not found + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/coroutine/coroutine-region-requirements.rs b/tests/ui/coroutine/coroutine-region-requirements.rs index 8bc34fdd2f053..ab6f16995e276 100644 --- a/tests/ui/coroutine/coroutine-region-requirements.rs +++ b/tests/ui/coroutine/coroutine-region-requirements.rs @@ -1,9 +1,9 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn dangle(x: &mut i32) -> &'static mut i32 { - let mut g = || { + let mut g = #[coroutine] || { yield; x }; diff --git a/tests/ui/coroutine/coroutine-resume-after-panic.rs b/tests/ui/coroutine/coroutine-resume-after-panic.rs index 8445bf7e6352c..2745ebc61326f 100644 --- a/tests/ui/coroutine/coroutine-resume-after-panic.rs +++ b/tests/ui/coroutine/coroutine-resume-after-panic.rs @@ -5,7 +5,7 @@ // Test that we get the correct message for resuming a panicked coroutine. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::Coroutine, @@ -14,7 +14,7 @@ use std::{ }; fn main() { - let mut g = || { + let mut g = #[coroutine] || { panic!(); yield; }; diff --git a/tests/ui/coroutine/coroutine-with-nll.rs b/tests/ui/coroutine/coroutine-with-nll.rs index 28a3643fbc9cd..fa77ab4e04958 100644 --- a/tests/ui/coroutine/coroutine-with-nll.rs +++ b/tests/ui/coroutine/coroutine-with-nll.rs @@ -1,6 +1,7 @@ #![feature(coroutines)] fn main() { + #[coroutine] || { // The reference in `_a` is a Legal with NLL since it ends before the yield let _a = &mut true; diff --git a/tests/ui/coroutine/coroutine-with-nll.stderr b/tests/ui/coroutine/coroutine-with-nll.stderr index 77e8bb1f92ee9..3f3d51da31180 100644 --- a/tests/ui/coroutine/coroutine-with-nll.stderr +++ b/tests/ui/coroutine/coroutine-with-nll.stderr @@ -1,5 +1,5 @@ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/coroutine-with-nll.rs:7:17 + --> $DIR/coroutine-with-nll.rs:8:17 | LL | let b = &mut true; | ^^^^^^^^^ diff --git a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs index 3c91b3c932951..f3110d71d0d72 100644 --- a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs +++ b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs @@ -1,5 +1,5 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] // Test that we cannot create a coroutine that returns a value of its // own type. @@ -12,7 +12,7 @@ pub fn want_cyclic_coroutine_return(_: T) } fn supply_cyclic_coroutine_return() { - want_cyclic_coroutine_return(|| { + want_cyclic_coroutine_return(#[coroutine] || { //~^ ERROR type mismatch if false { yield None.unwrap(); } None.unwrap() @@ -25,7 +25,7 @@ pub fn want_cyclic_coroutine_yield(_: T) } fn supply_cyclic_coroutine_yield() { - want_cyclic_coroutine_yield(|| { + want_cyclic_coroutine_yield(#[coroutine] || { //~^ ERROR type mismatch if false { yield None.unwrap(); } None.unwrap() diff --git a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr index 325030524ba8d..32799148ae1da 100644 --- a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr +++ b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36}` - --> $DIR/coroutine-yielding-or-returning-itself.rs:15:34 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49}` + --> $DIR/coroutine-yielding-or-returning-itself.rs:15:47 | -LL | want_cyclic_coroutine_return(|| { - | _____----------------------------_^ +LL | want_cyclic_coroutine_return(#[coroutine] || { + | _____----------------------------______________^ | | | | | required by a bound introduced by this call LL | | @@ -23,11 +23,11 @@ LL | pub fn want_cyclic_coroutine_return(_: T) LL | where T: Coroutine | ^^^^^^^^^^ required by this bound in `want_cyclic_coroutine_return` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35}` - --> $DIR/coroutine-yielding-or-returning-itself.rs:28:33 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48}` + --> $DIR/coroutine-yielding-or-returning-itself.rs:28:46 | -LL | want_cyclic_coroutine_yield(|| { - | _____---------------------------_^ +LL | want_cyclic_coroutine_yield(#[coroutine] || { + | _____---------------------------______________^ | | | | | required by a bound introduced by this call LL | | diff --git a/tests/ui/coroutine/derived-drop-parent-expr.rs b/tests/ui/coroutine/derived-drop-parent-expr.rs index f70a732c90f08..cc217e4960e90 100644 --- a/tests/ui/coroutine/derived-drop-parent-expr.rs +++ b/tests/ui/coroutine/derived-drop-parent-expr.rs @@ -1,7 +1,7 @@ //@ build-pass //! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn assert_send(_thing: T) {} @@ -9,8 +9,8 @@ fn assert_send(_thing: T) {} pub struct Client { pub nickname: String } fn main() { - let g = move || match drop(Client { ..Client::default() }) { - _status => yield, - }; + let g = #[coroutine] move || match drop(Client { ..Client::default() }) { + _status => yield, + }; assert_send(g); } diff --git a/tests/ui/coroutine/discriminant.rs b/tests/ui/coroutine/discriminant.rs index a44d8f74746b6..d6879e2182556 100644 --- a/tests/ui/coroutine/discriminant.rs +++ b/tests/ui/coroutine/discriminant.rs @@ -86,7 +86,7 @@ fn cycle( fn main() { // Has only one invalid discr. value. let gen_u8_tiny_niche = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants @@ -98,7 +98,7 @@ fn main() { // Uses all values in the u8 discriminant. let gen_u8_full = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants @@ -111,7 +111,7 @@ fn main() { // Barely needs a u16 discriminant. let gen_u16 = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants diff --git a/tests/ui/coroutine/drop-and-replace.rs b/tests/ui/coroutine/drop-and-replace.rs index 6e30d76512b72..d3d7e000020a1 100644 --- a/tests/ui/coroutine/drop-and-replace.rs +++ b/tests/ui/coroutine/drop-and-replace.rs @@ -4,7 +4,7 @@ // #60187, this produced incorrect code for coroutines when a saved local was // re-assigned. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -17,7 +17,8 @@ impl Drop for Foo { } fn main() { - let mut a = || { + let mut a = #[coroutine] + || { let mut x = Foo(4); yield; assert_eq!(x.0, 4); diff --git a/tests/ui/coroutine/drop-control-flow.rs b/tests/ui/coroutine/drop-control-flow.rs index f4e8eed4f8dce..f576b1b759443 100644 --- a/tests/ui/coroutine/drop-control-flow.rs +++ b/tests/ui/coroutine/drop-control-flow.rs @@ -4,7 +4,7 @@ // and also that values that are dropped along all paths to a yield do not get // included in the coroutine type. -#![feature(coroutines, negative_impls)] +#![feature(coroutines, negative_impls, stmt_expr_attributes)] #![allow(unused_assignments, dead_code)] struct Ptr; @@ -19,7 +19,7 @@ fn assert_send(_: T) {} // This test case is reduced from tests/ui/drop/dynamic-drop-async.rs fn one_armed_if(arg: bool) { - let _ = || { + let _ = #[coroutine] || { let arr = [Ptr]; if arg { drop(arr); @@ -29,7 +29,7 @@ fn one_armed_if(arg: bool) { } fn two_armed_if(arg: bool) { - assert_send(|| { + assert_send(#[coroutine] || { let arr = [Ptr]; if arg { drop(arr); @@ -41,7 +41,7 @@ fn two_armed_if(arg: bool) { } fn if_let(arg: Option) { - let _ = || { + let _ = #[coroutine] || { let arr = [Ptr]; if let Some(_) = arg { drop(arr); @@ -51,7 +51,7 @@ fn if_let(arg: Option) { } fn init_in_if(arg: bool) { - assert_send(|| { + assert_send(#[coroutine] || { let mut x = NonSend; drop(x); if arg { @@ -63,7 +63,7 @@ fn init_in_if(arg: bool) { } fn init_in_match_arm(arg: Option) { - assert_send(|| { + assert_send(#[coroutine] || { let mut x = NonSend; drop(x); match arg { @@ -74,7 +74,7 @@ fn init_in_match_arm(arg: Option) { } fn reinit() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; drop(arr); arr = [Ptr]; @@ -83,7 +83,7 @@ fn reinit() { } fn loop_uninit() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); @@ -96,7 +96,7 @@ fn loop_uninit() { } fn nested_loop() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); @@ -111,7 +111,7 @@ fn nested_loop() { } fn loop_continue(b: bool) { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); diff --git a/tests/ui/coroutine/drop-env.rs b/tests/ui/coroutine/drop-env.rs index b189ab8149956..d36228dc84904 100644 --- a/tests/ui/coroutine/drop-env.rs +++ b/tests/ui/coroutine/drop-env.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(dropping_copy_types)] use std::ops::Coroutine; @@ -28,7 +28,7 @@ fn main() { fn t1() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] || { yield; drop(b); }; @@ -42,7 +42,7 @@ fn t1() { fn t2() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] || { yield b; }; @@ -55,7 +55,7 @@ fn t2() { fn t3() { let b = B; - let foo = || { + let foo = #[coroutine] || { yield; drop(b); }; diff --git a/tests/ui/coroutine/drop-track-addassign-yield.rs b/tests/ui/coroutine/drop-track-addassign-yield.rs index b1a4bd79f31c1..537e66c41b20b 100644 --- a/tests/ui/coroutine/drop-track-addassign-yield.rs +++ b/tests/ui/coroutine/drop-track-addassign-yield.rs @@ -3,10 +3,10 @@ // Based on addassign-yield.rs, but with drop tracking enabled. Originally we did not implement // the fake_read callback on ExprUseVisitor which caused this case to break. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo() { - let _y = static || { + let _y = #[coroutine] static || { let x = &mut 0; *{ yield; @@ -17,7 +17,7 @@ fn foo() { }; // Please don't ever actually write something like this - let _z = static || { + let _z = #[coroutine] static || { let x = &mut 0; *{ let inner = &mut 1; diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.rs b/tests/ui/coroutine/drop-tracking-parent-expression.rs index 4d40192c07a27..0f4d99c893648 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.rs +++ b/tests/ui/coroutine/drop-tracking-parent-expression.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, negative_impls, rustc_attrs)] +#![feature(coroutines, negative_impls, rustc_attrs, stmt_expr_attributes)] macro_rules! type_combinations { ( @@ -14,7 +14,7 @@ macro_rules! type_combinations { // Struct update syntax. This fails because the Client used in the update is considered // dropped *after* the yield. { - let g = move || match drop($name::Client { ..$name::Client::default() }) { + let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { //~^ `significant_drop::Client` which is not `Send` //~| `insignificant_dtor::Client` which is not `Send` //~| `derived_drop::Client` which is not `Send` @@ -29,7 +29,7 @@ macro_rules! type_combinations { // Simple owned value. This works because the Client is considered moved into `drop`, // even though the temporary expression doesn't end until after the yield. { - let g = move || match drop($name::Client::default()) { + let g = #[coroutine] move || match drop($name::Client::default()) { _ => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr index 21aa35b9579bc..5f8d8495e4f14 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr +++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr @@ -13,12 +13,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -53,12 +53,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -93,12 +93,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later diff --git a/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs b/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs index 0f94016f11b82..43e42fa85f7f4 100644 --- a/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs +++ b/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs @@ -1,10 +1,10 @@ //@ build-pass //@ edition:2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _ = static |x: u8| match x { + let _ = #[coroutine] static |x: u8| match x { y if { yield } == y + 1 => (), _ => (), }; diff --git a/tests/ui/coroutine/drop-yield-twice.rs b/tests/ui/coroutine/drop-yield-twice.rs index 015343a277626..7ac1345b2ff2e 100644 --- a/tests/ui/coroutine/drop-yield-twice.rs +++ b/tests/ui/coroutine/drop-yield-twice.rs @@ -1,10 +1,10 @@ -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo(i32); impl !Send for Foo {} fn main() { - assert_send(|| { //~ ERROR coroutine cannot be sent between threads safely + assert_send(#[coroutine] || { //~ ERROR coroutine cannot be sent between threads safely let guard = Foo(42); yield; drop(guard); diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr index c6a9e20b8b51f..362c6e943ade0 100644 --- a/tests/ui/coroutine/drop-yield-twice.stderr +++ b/tests/ui/coroutine/drop-yield-twice.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-yield-twice.rs:7:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | let guard = Foo(42); LL | | yield; LL | | drop(guard); @@ -9,7 +9,7 @@ LL | | yield; LL | | }) | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}: Send` + = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/tests/ui/coroutine/dropck-resume.rs b/tests/ui/coroutine/dropck-resume.rs index 07ca4d37aba69..df014400f00fe 100644 --- a/tests/ui/coroutine/dropck-resume.rs +++ b/tests/ui/coroutine/dropck-resume.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -16,7 +16,8 @@ fn drop_using_coroutine() -> i32 { let z = &mut y; let r; { - let mut g = move |r| { + let mut g = #[coroutine] + move |r| { let _s = SetToNone(r); yield; }; diff --git a/tests/ui/coroutine/dropck-resume.stderr b/tests/ui/coroutine/dropck-resume.stderr index aa6e423c7604c..e9243ffa41e5d 100644 --- a/tests/ui/coroutine/dropck-resume.stderr +++ b/tests/ui/coroutine/dropck-resume.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/dropck-resume.rs:25:13 + --> $DIR/dropck-resume.rs:26:13 | LL | let z = &mut y; | ------ mutable borrow occurs here diff --git a/tests/ui/coroutine/dropck.rs b/tests/ui/coroutine/dropck.rs index 450361c8dd03b..9331c1fa1d580 100644 --- a/tests/ui/coroutine/dropck.rs +++ b/tests/ui/coroutine/dropck.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::cell::RefCell; use std::ops::Coroutine; @@ -10,7 +10,8 @@ fn main() { let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); //~^ ERROR `*cell` does not live long enough [E0597] // the upvar is the non-dropck `&mut Option>`. - gen = || { + gen = #[coroutine] + || { // but the coroutine can use it to drop a `Ref<'a, i32>`. let _d = ref_.take(); //~ ERROR `ref_` does not live long enough yield; diff --git a/tests/ui/coroutine/dropck.stderr b/tests/ui/coroutine/dropck.stderr index 241d6dfe0a169..78fdeec972f79 100644 --- a/tests/ui/coroutine/dropck.stderr +++ b/tests/ui/coroutine/dropck.stderr @@ -16,10 +16,13 @@ LL | } = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough - --> $DIR/dropck.rs:15:18 + --> $DIR/dropck.rs:16:18 | -LL | gen = || { - | -- value captured here by coroutine +LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); + | ---- binding `ref_` declared here +... +LL | || { + | -- value captured here by coroutine LL | // but the coroutine can use it to drop a `Ref<'a, i32>`. LL | let _d = ref_.take(); | ^^^^ borrowed value does not live long enough diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr index 2b9eb4a820b65..322259cf2f84f 100644 --- a/tests/ui/coroutine/gen_block.e2024.stderr +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -1,5 +1,25 @@ +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:20:13 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:24:13 + | +LL | let _ = #[coroutine] || {}; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -8,13 +28,34 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/gen_block.rs:16:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0282]: type annotations needed - --> $DIR/gen_block.rs:6:13 + --> $DIR/gen_block.rs:7:13 | LL | let x = gen {}; | ^^^^^^ cannot infer type -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0282, E0658. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr index 78a8c5e798ad8..64fa2be003de5 100644 --- a/tests/ui/coroutine/gen_block.none.stderr +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -1,5 +1,5 @@ error: expected identifier, found reserved keyword `yield` - --> $DIR/gen_block.rs:9:19 + --> $DIR/gen_block.rs:10:19 | LL | let y = gen { yield 42 }; | --- ^^^^^ expected identifier, found reserved keyword @@ -7,25 +7,25 @@ LL | let y = gen { yield 42 }; | while parsing this struct error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:6:13 + --> $DIR/gen_block.rs:7:13 | LL | let x = gen {}; | ^^^ not found in this scope error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:9:13 + --> $DIR/gen_block.rs:10:13 | LL | let y = gen { yield 42 }; | ^^^ not found in this scope error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:12:5 + --> $DIR/gen_block.rs:13:5 | LL | gen {}; | ^^^ not found in this scope error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -35,17 +35,69 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:20:13 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:24:13 + | +LL | let _ = #[coroutine] || {}; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:16:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | = note: see issue #43122 for more information = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 6 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0422, E0658. For more information about an error, try `rustc --explain E0422`. diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs index f6a775aa66199..7e87a572b9095 100644 --- a/tests/ui/coroutine/gen_block.rs +++ b/tests/ui/coroutine/gen_block.rs @@ -1,6 +1,7 @@ //@ revisions: e2024 none //@[e2024] compile-flags: --edition 2024 -Zunstable-options #![cfg_attr(e2024, feature(gen_blocks))] +#![feature(stmt_expr_attributes)] fn main() { let x = gen {}; @@ -14,4 +15,12 @@ fn main() { let _ = || yield true; //[none]~ ERROR yield syntax is experimental //~^ ERROR yield syntax is experimental + //~^^ ERROR `yield` can only be used in + + let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental + //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^^ ERROR yield syntax is experimental + + let _ = #[coroutine] || {}; + //~^ ERROR `#[coroutines]` attribute is an experimental feature } diff --git a/tests/ui/coroutine/issue-102645.rs b/tests/ui/coroutine/issue-102645.rs index a0263510e1368..ccf82c3606ac2 100644 --- a/tests/ui/coroutine/issue-102645.rs +++ b/tests/ui/coroutine/issue-102645.rs @@ -1,11 +1,12 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let d = 6; yield; _zzz(); // #break diff --git a/tests/ui/coroutine/issue-102645.stderr b/tests/ui/coroutine/issue-102645.stderr index 7a3b7f2b04c34..ab5e4a8459f4f 100644 --- a/tests/ui/coroutine/issue-102645.stderr +++ b/tests/ui/coroutine/issue-102645.stderr @@ -1,5 +1,5 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied - --> $DIR/issue-102645.rs:14:22 + --> $DIR/issue-102645.rs:15:22 | LL | Pin::new(&mut b).resume(); | ^^^^^^-- an argument of type `()` is missing diff --git a/tests/ui/coroutine/issue-105084.rs b/tests/ui/coroutine/issue-105084.rs index 7801f1bcea0db..4e40bc127d780 100644 --- a/tests/ui/coroutine/issue-105084.rs +++ b/tests/ui/coroutine/issue-105084.rs @@ -11,7 +11,8 @@ fn copy(x: T) -> T { } fn main() { - let mut g = || { + let mut g = #[coroutine] + || { // This is desuraged as 4 stages: // - allocate a `*mut u8` with `exchange_malloc`; // - create a Box that is ignored for trait computations; diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr index c8a6522dbd938..6b1701f0c2abc 100644 --- a/tests/ui/coroutine/issue-105084.stderr +++ b/tests/ui/coroutine/issue-105084.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `g` - --> $DIR/issue-105084.rs:37:14 + --> $DIR/issue-105084.rs:38:14 | -LL | let mut g = || { - | ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, which does not implement the `Copy` trait +LL | let mut g = #[coroutine] + | ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, which does not implement the `Copy` trait ... LL | let mut h = copy(g); | - value moved here @@ -22,17 +22,17 @@ help: consider cloning the value if the performance cost is acceptable LL | let mut h = copy(g.clone()); | ++++++++ -error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}` - --> $DIR/issue-105084.rs:31:17 +error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}` + --> $DIR/issue-105084.rs:32:17 | -LL | let mut g = || { - | -- within this `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}` +LL | || { + | -- within this `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}` ... LL | let mut h = copy(g); - | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}: Copy` + | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/issue-105084.rs:21:22 + --> $DIR/issue-105084.rs:22:22 | LL | Box::new((5, yield)); | -------------^^^^^-- diff --git a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs index 3d372ac9110c9..300c8fe6d4618 100644 --- a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs +++ b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs @@ -1,11 +1,12 @@ //@ edition:2021 //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let x = &mut (); || { - let _c = || yield *&mut *x; + let _c = #[coroutine] + || yield *&mut *x; || _ = &mut *x; }; } diff --git a/tests/ui/coroutine/issue-113279.rs b/tests/ui/coroutine/issue-113279.rs index f251c924c1331..98617af105c35 100644 --- a/tests/ui/coroutine/issue-113279.rs +++ b/tests/ui/coroutine/issue-113279.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] // `foo` attempts to dereference `""`, which results in an error being reported. Later, the // coroutine transform for `foo` then produces a union which contains a `str` type - unions should @@ -9,7 +9,8 @@ // makes sure that doesn't happen again. fn foo() { - let _y = static || { + let _y = #[coroutine] + static || { let x = &mut 0; *{ yield; diff --git a/tests/ui/coroutine/issue-113279.stderr b/tests/ui/coroutine/issue-113279.stderr index cc9b64ef9ac2f..a80fe670188d6 100644 --- a/tests/ui/coroutine/issue-113279.stderr +++ b/tests/ui/coroutine/issue-113279.stderr @@ -1,11 +1,11 @@ error[E0161]: cannot move a value of type `str` - --> $DIR/issue-113279.rs:17:20 + --> $DIR/issue-113279.rs:18:20 | LL | } += match { *"" }.len() { | ^^^^^^^ the size of `str` cannot be statically determined error[E0507]: cannot move out of a shared reference - --> $DIR/issue-113279.rs:17:22 + --> $DIR/issue-113279.rs:18:22 | LL | } += match { *"" }.len() { | ^^^ move occurs because value has type `str`, which does not implement the `Copy` trait diff --git a/tests/ui/coroutine/issue-44197.rs b/tests/ui/coroutine/issue-44197.rs index e18bcc2c996f2..0240f7a7eaac2 100644 --- a/tests/ui/coroutine/issue-44197.rs +++ b/tests/ui/coroutine/issue-44197.rs @@ -10,7 +10,7 @@ fn foo(_: &str) -> String { } fn bar(baz: String) -> impl Coroutine<(), Yield = String, Return = ()> { - move || { + #[coroutine] move || { yield foo(&baz); } } @@ -20,7 +20,7 @@ fn foo2(_: &str) -> Result { } fn bar2(baz: String) -> impl Coroutine<(), Yield = String, Return = ()> { - move || { + #[coroutine] move || { if let Ok(quux) = foo2(&baz) { yield quux; } diff --git a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs index dab9c81bc8fe8..d90886b6b1d6e 100644 --- a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs +++ b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs @@ -1,7 +1,8 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _ = || { + let _ = #[coroutine] + || { *(1 as *mut u32) = 42; //~^ ERROR dereference of raw pointer is unsafe yield; diff --git a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr index 19949b4293962..f99c295bb9ebf 100644 --- a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr +++ b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45729-unsafe-in-coroutine.rs:5:9 + --> $DIR/issue-45729-unsafe-in-coroutine.rs:6:9 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/tests/ui/coroutine/issue-48048.rs b/tests/ui/coroutine/issue-48048.rs index b61b7c7707235..75664f20198b5 100644 --- a/tests/ui/coroutine/issue-48048.rs +++ b/tests/ui/coroutine/issue-48048.rs @@ -3,7 +3,7 @@ fn main() { let x = (|_| {},); - || { + #[coroutine] || { let x = x; x.0({ //~ ERROR borrow may still be in use when coroutine yields diff --git a/tests/ui/coroutine/issue-52304.rs b/tests/ui/coroutine/issue-52304.rs index 01ed181ab1dcb..552bc0028ee04 100644 --- a/tests/ui/coroutine/issue-52304.rs +++ b/tests/ui/coroutine/issue-52304.rs @@ -5,6 +5,7 @@ use std::ops::Coroutine; pub fn example() -> impl Coroutine { + #[coroutine] || yield &1 } diff --git a/tests/ui/coroutine/issue-52398.rs b/tests/ui/coroutine/issue-52398.rs index 826ce6b9d9b3f..f8b2faf4eabf0 100644 --- a/tests/ui/coroutine/issue-52398.rs +++ b/tests/ui/coroutine/issue-52398.rs @@ -14,14 +14,14 @@ impl A { fn main() { // Test that the MIR local with type &A created for the auto-borrow adjustment // is caught by typeck - move || { //~ WARN unused coroutine that must be used + #[coroutine] move || { //~ WARN unused coroutine that must be used A.test(yield); }; // Test that the std::cell::Ref temporary returned from the `borrow` call // is caught by typeck let y = RefCell::new(true); - static move || { //~ WARN unused coroutine that must be used + #[coroutine] static move || { //~ WARN unused coroutine that must be used yield *y.borrow(); return "Done"; }; diff --git a/tests/ui/coroutine/issue-52398.stderr b/tests/ui/coroutine/issue-52398.stderr index 18d816da4c611..806690cc33276 100644 --- a/tests/ui/coroutine/issue-52398.stderr +++ b/tests/ui/coroutine/issue-52398.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-52398.rs:17:5 + --> $DIR/issue-52398.rs:17:18 | -LL | / move || { +LL | #[coroutine] move || { + | __________________^ LL | | A.test(yield); LL | | }; | |_____^ @@ -10,9 +11,10 @@ LL | | }; = note: `#[warn(unused_must_use)]` on by default warning: unused coroutine that must be used - --> $DIR/issue-52398.rs:24:5 + --> $DIR/issue-52398.rs:24:18 | -LL | / static move || { +LL | #[coroutine] static move || { + | __________________^ LL | | yield *y.borrow(); LL | | return "Done"; LL | | }; diff --git a/tests/ui/coroutine/issue-53548.rs b/tests/ui/coroutine/issue-53548.rs index 6d55994137ff9..3b8dff2be28c1 100644 --- a/tests/ui/coroutine/issue-53548.rs +++ b/tests/ui/coroutine/issue-53548.rs @@ -17,7 +17,7 @@ // //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] use std::cell::RefCell; use std::rc::Rc; @@ -29,7 +29,7 @@ struct Store { } fn main() { - Box::new(static move || { + Box::new(#[coroutine] static move || { let store = Store::> { inner: Default::default(), }; diff --git a/tests/ui/coroutine/issue-57017.rs b/tests/ui/coroutine/issue-57017.rs index b83d916932abd..19cd80ab4a653 100644 --- a/tests/ui/coroutine/issue-57017.rs +++ b/tests/ui/coroutine/issue-57017.rs @@ -1,5 +1,5 @@ //@ build-pass -#![feature(coroutines, negative_impls)] +#![feature(coroutines, negative_impls, stmt_expr_attributes)] #![allow(dropping_references, dropping_copy_types)] macro_rules! type_combinations { @@ -21,7 +21,7 @@ macro_rules! type_combinations { // This is the same bug as issue 57017, but using yield instead of await { - let g = move || match drop(&$name::unsync::Client::default()) { + let g = #[coroutine] move || match drop(&$name::unsync::Client::default()) { _status => yield, }; assert_send(g); @@ -30,7 +30,7 @@ macro_rules! type_combinations { // This tests that `Client` is properly considered to be dropped after moving it into the // function. { - let g = move || match drop($name::unsend::Client::default()) { + let g = #[coroutine] move || match drop($name::unsend::Client::default()) { _status => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/issue-57084.rs b/tests/ui/coroutine/issue-57084.rs index 51b0c8e1de96c..2df60550e0378 100644 --- a/tests/ui/coroutine/issue-57084.rs +++ b/tests/ui/coroutine/issue-57084.rs @@ -8,7 +8,7 @@ use std::ops::Coroutine; fn with(f: F) -> impl Coroutine where F: Fn() -> () { - move || { + #[coroutine] move || { loop { match f() { _ => yield, @@ -19,7 +19,7 @@ where F: Fn() -> () fn main() { let data = &vec![1]; - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used let _to_pin = with(move || println!("{:p}", data)); loop { yield diff --git a/tests/ui/coroutine/issue-57084.stderr b/tests/ui/coroutine/issue-57084.stderr index 9f5b79a6ae8af..81bd27da91905 100644 --- a/tests/ui/coroutine/issue-57084.stderr +++ b/tests/ui/coroutine/issue-57084.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-57084.rs:22:5 + --> $DIR/issue-57084.rs:22:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let _to_pin = with(move || println!("{:p}", data)); LL | | loop { LL | | yield diff --git a/tests/ui/coroutine/issue-57478.rs b/tests/ui/coroutine/issue-57478.rs index 5e479aaa9c1b3..494c2ee9843eb 100644 --- a/tests/ui/coroutine/issue-57478.rs +++ b/tests/ui/coroutine/issue-57478.rs @@ -1,16 +1,19 @@ //@ check-pass -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo; impl !Send for Foo {} fn main() { - assert_send(|| { - let guard = Foo; - drop(guard); - yield; - }) + assert_send( + #[coroutine] + || { + let guard = Foo; + drop(guard); + yield; + }, + ) } fn assert_send(_: T) {} diff --git a/tests/ui/coroutine/issue-58888.rs b/tests/ui/coroutine/issue-58888.rs index ce45f22dd6ef3..6266f97ce8c46 100644 --- a/tests/ui/coroutine/issue-58888.rs +++ b/tests/ui/coroutine/issue-58888.rs @@ -13,7 +13,7 @@ impl Database { } fn check_connection(&self) -> impl Coroutine + '_ { - move || { + #[coroutine] move || { let iter = self.get_connection(); for i in iter { yield i diff --git a/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs b/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs index 6280b777201fb..6f513c250a554 100644 --- a/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs +++ b/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs @@ -4,7 +4,7 @@ //@ check-pass //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -14,12 +14,14 @@ async fn drop_and_await() { } fn drop_and_yield() { - let x = || { + let x = #[coroutine] + || { String::new(); yield; }; Box::pin(x).as_mut().resume(()); - let y = static || { + let y = #[coroutine] + static || { String::new(); yield; }; diff --git a/tests/ui/coroutine/issue-64620-yield-array-element.rs b/tests/ui/coroutine/issue-64620-yield-array-element.rs index a9307d306a617..0d898d014e80b 100644 --- a/tests/ui/coroutine/issue-64620-yield-array-element.rs +++ b/tests/ui/coroutine/issue-64620-yield-array-element.rs @@ -4,6 +4,7 @@ pub fn crash(arr: [usize; 1]) { yield arr[0]; //~ ERROR: yield expression outside of coroutine literal + //~^ ERROR: `yield` can only be used in } fn main() {} diff --git a/tests/ui/coroutine/issue-64620-yield-array-element.stderr b/tests/ui/coroutine/issue-64620-yield-array-element.stderr index 347532fb7193e..1c030c5248e1e 100644 --- a/tests/ui/coroutine/issue-64620-yield-array-element.stderr +++ b/tests/ui/coroutine/issue-64620-yield-array-element.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/issue-64620-yield-array-element.rs:6:5 + | +LL | yield arr[0]; + | ^^^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] pub fn crash(arr: [usize; 1]) { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/issue-64620-yield-array-element.rs:6:5 | LL | yield arr[0]; | ^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/issue-68112.rs b/tests/ui/coroutine/issue-68112.rs index ccec2acc97623..b296772c90577 100644 --- a/tests/ui/coroutine/issue-68112.rs +++ b/tests/ui/coroutine/issue-68112.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ cell::RefCell, @@ -30,7 +30,7 @@ fn make_non_send_coroutine() -> impl Coroutine>> { } fn test1() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine(); //~^ NOTE not `Send` yield; @@ -46,7 +46,7 @@ fn test1() { pub fn make_gen2(t: T) -> impl Coroutine { //~^ NOTE appears within the type //~| NOTE expansion of desugaring - || { //~ NOTE used within this coroutine + #[coroutine] || { //~ NOTE used within this coroutine yield; t } @@ -57,7 +57,7 @@ fn make_non_send_coroutine2() -> impl Coroutine>> { // } fn test2() { - let send_gen = || { //~ NOTE used within this coroutine + let send_gen = #[coroutine] || { //~ NOTE used within this coroutine let _non_send_gen = make_non_send_coroutine2(); yield; }; diff --git a/tests/ui/coroutine/issue-68112.stderr b/tests/ui/coroutine/issue-68112.stderr index 443195d36a30a..bcfcb5ec6e608 100644 --- a/tests/ui/coroutine/issue-68112.stderr +++ b/tests/ui/coroutine/issue-68112.stderr @@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:33:20: 33:22}: Send` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:33:33: 33:35}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:36:9 @@ -26,14 +26,14 @@ error[E0277]: `RefCell` cannot be shared between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:60:20: 60:22}: Send` + = help: the trait `Sync` is not implemented for `RefCell`, which is required by `{coroutine@$DIR/issue-68112.rs:60:33: 60:35}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this coroutine - --> $DIR/issue-68112.rs:49:5 + --> $DIR/issue-68112.rs:49:18 | -LL | || { - | ^^ +LL | #[coroutine] || { + | ^^ note: required because it appears within the type `impl Coroutine>>` --> $DIR/issue-68112.rs:46:30 | @@ -45,10 +45,10 @@ note: required because it appears within the type `impl Coroutine impl Coroutine>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it's used within this coroutine - --> $DIR/issue-68112.rs:60:20 + --> $DIR/issue-68112.rs:60:33 | -LL | let send_gen = || { - | ^^ +LL | let send_gen = #[coroutine] || { + | ^^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:22:25 | diff --git a/tests/ui/coroutine/issue-69017.rs b/tests/ui/coroutine/issue-69017.rs index 09bbf63a986e5..bf69e1dfdb13f 100644 --- a/tests/ui/coroutine/issue-69017.rs +++ b/tests/ui/coroutine/issue-69017.rs @@ -10,6 +10,7 @@ use std::ops::Coroutine; fn gen() -> impl Coroutine { + #[coroutine] |_: usize| { println!("-> {}", yield); } diff --git a/tests/ui/coroutine/issue-69039.rs b/tests/ui/coroutine/issue-69039.rs index fd12414c3d851..13cb50e582817 100644 --- a/tests/ui/coroutine/issue-69039.rs +++ b/tests/ui/coroutine/issue-69039.rs @@ -9,6 +9,7 @@ fn mkstr(my_name: String, my_mood: String) -> String { } fn my_scenario() -> impl Coroutine { + #[coroutine] |_arg: String| { let my_name = yield "What is your name?"; let my_mood = yield "How are you feeling?"; diff --git a/tests/ui/coroutine/issue-87142.rs b/tests/ui/coroutine/issue-87142.rs index f5c3805842c51..6c22ba3dd7560 100644 --- a/tests/ui/coroutine/issue-87142.rs +++ b/tests/ui/coroutine/issue-87142.rs @@ -22,6 +22,7 @@ pub struct Context { impl CoroutineProviderAlt for () { type Coro = impl Coroutine<(), Return = (), Yield = ()>; fn start(ctx: Context) -> Self::Coro { + #[coroutine] move || { match ctx { _ => (), diff --git a/tests/ui/coroutine/issue-88653.rs b/tests/ui/coroutine/issue-88653.rs index ec4c205475877..3afd12a209379 100644 --- a/tests/ui/coroutine/issue-88653.rs +++ b/tests/ui/coroutine/issue-88653.rs @@ -11,6 +11,7 @@ fn foo(bar: bool) -> impl Coroutine<(bool,)> { //~| NOTE: expected coroutine signature `fn((bool,)) -> _` //~| NOTE: in this expansion of desugaring of `impl Trait` //~| NOTE: in this expansion of desugaring of `impl Trait` + #[coroutine] |bar| { //~^ NOTE: found signature defined here if bar { diff --git a/tests/ui/coroutine/issue-91477.rs b/tests/ui/coroutine/issue-91477.rs index c98546f7971cf..c215fd7948f33 100644 --- a/tests/ui/coroutine/issue-91477.rs +++ b/tests/ui/coroutine/issue-91477.rs @@ -2,6 +2,7 @@ fn foo() -> impl Sized { yield 1; //~ ERROR E0627 + //~^ ERROR: `yield` can only be used in } fn main() {} diff --git a/tests/ui/coroutine/issue-91477.stderr b/tests/ui/coroutine/issue-91477.stderr index ca8e43d8a26db..5e2151c4c35fe 100644 --- a/tests/ui/coroutine/issue-91477.stderr +++ b/tests/ui/coroutine/issue-91477.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/issue-91477.rs:4:5 + | +LL | yield 1; + | ^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn foo() -> impl Sized { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/issue-91477.rs:4:5 | LL | yield 1; | ^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/iterator-count.rs b/tests/ui/coroutine/iterator-count.rs index bb202ab2d33ed..1ca8ceaed2a9e 100644 --- a/tests/ui/coroutine/iterator-count.rs +++ b/tests/ui/coroutine/iterator-count.rs @@ -21,6 +21,7 @@ impl + Unpin> Iterator for W { } fn test() -> impl Coroutine<(), Return = (), Yield = u8> + Unpin { + #[coroutine] || { for i in 1..6 { yield i @@ -32,6 +33,7 @@ fn main() { let end = 11; let closure_test = |start| { + #[coroutine] move || { for i in start..end { yield i diff --git a/tests/ui/coroutine/live-upvar-across-yield.rs b/tests/ui/coroutine/live-upvar-across-yield.rs index 86c4716c9516d..d13d480dcdcce 100644 --- a/tests/ui/coroutine/live-upvar-across-yield.rs +++ b/tests/ui/coroutine/live-upvar-across-yield.rs @@ -1,13 +1,13 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let b = |_| 3; - let mut a = || { + let mut a = #[coroutine] || { b(yield); }; Pin::new(&mut a).resume(()); diff --git a/tests/ui/coroutine/match-bindings.rs b/tests/ui/coroutine/match-bindings.rs index 9ea1deaab3623..2a0cd9af9f382 100644 --- a/tests/ui/coroutine/match-bindings.rs +++ b/tests/ui/coroutine/match-bindings.rs @@ -9,7 +9,7 @@ enum Enum { } fn main() { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used loop { if let true = true { match Enum::A(String::new()) { diff --git a/tests/ui/coroutine/match-bindings.stderr b/tests/ui/coroutine/match-bindings.stderr index a7aa6eadb95f1..5525bfed1165b 100644 --- a/tests/ui/coroutine/match-bindings.stderr +++ b/tests/ui/coroutine/match-bindings.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/match-bindings.rs:12:5 + --> $DIR/match-bindings.rs:12:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | loop { LL | | if let true = true { LL | | match Enum::A(String::new()) { diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed new file mode 100644 index 0000000000000..128f09a118439 --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed @@ -0,0 +1,8 @@ +//@ run-rustfix + +#![feature(coroutines, gen_blocks, stmt_expr_attributes)] + +fn main() { + let _ = #[coroutine] || yield; + //~^ ERROR `yield` can only be used +} diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs new file mode 100644 index 0000000000000..dc95259149609 --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs @@ -0,0 +1,8 @@ +//@ run-rustfix + +#![feature(coroutines, gen_blocks, stmt_expr_attributes)] + +fn main() { + let _ = || yield; + //~^ ERROR `yield` can only be used +} diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr b/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr new file mode 100644 index 0000000000000..8d92471a361cd --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr @@ -0,0 +1,13 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/missing_coroutine_attr_suggestion.rs:6:16 + | +LL | let _ = || yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield; + | ++++++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/coroutine/nested_coroutine.rs b/tests/ui/coroutine/nested_coroutine.rs index 7ff97abf4bb1f..2c12ab2adad41 100644 --- a/tests/ui/coroutine/nested_coroutine.rs +++ b/tests/ui/coroutine/nested_coroutine.rs @@ -1,13 +1,15 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let _coroutine = || { - let mut sub_coroutine = || { + let _coroutine = #[coroutine] + || { + let mut sub_coroutine = #[coroutine] + || { yield 2; }; diff --git a/tests/ui/coroutine/niche-in-coroutine.rs b/tests/ui/coroutine/niche-in-coroutine.rs index 45b920ab9273e..117ee9e6f0386 100644 --- a/tests/ui/coroutine/niche-in-coroutine.rs +++ b/tests/ui/coroutine/niche-in-coroutine.rs @@ -2,7 +2,7 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] use std::mem::size_of_val; @@ -10,7 +10,7 @@ fn take(_: T) {} fn main() { let x = false; - let gen1 = || { + let gen1 = #[coroutine] || { yield; take(x); }; diff --git a/tests/ui/coroutine/non-static-is-unpin.rs b/tests/ui/coroutine/non-static-is-unpin.rs index 616a78d5fe2a2..b28bf1977145b 100644 --- a/tests/ui/coroutine/non-static-is-unpin.rs +++ b/tests/ui/coroutine/non-static-is-unpin.rs @@ -3,7 +3,7 @@ //@[next] compile-flags: -Znext-solver //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(dropping_copy_types)] use std::marker::PhantomPinned; @@ -14,7 +14,7 @@ fn assert_unpin(_: G) { fn main() { // Even though this coroutine holds a `PhantomPinned` in its environment, it // remains `Unpin`. - assert_unpin(|| { + assert_unpin(#[coroutine] || { let pinned = PhantomPinned; yield; drop(pinned); diff --git a/tests/ui/coroutine/not-send-sync.rs b/tests/ui/coroutine/not-send-sync.rs index dd6182c10de09..a46dcd14e8825 100644 --- a/tests/ui/coroutine/not-send-sync.rs +++ b/tests/ui/coroutine/not-send-sync.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(negative_impls)] struct NotSend; @@ -11,14 +11,14 @@ fn main() { fn assert_sync(_: T) {} fn assert_send(_: T) {} - assert_sync(|| { + assert_sync(#[coroutine] || { //~^ ERROR: coroutine cannot be shared between threads safely let a = NotSync; yield; drop(a); }); - assert_send(|| { + assert_send(#[coroutine] || { //~^ ERROR: coroutine cannot be sent between threads safely let a = NotSend; yield; diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr index 9228340c710dd..0f9cbdec1300e 100644 --- a/tests/ui/coroutine/not-send-sync.stderr +++ b/tests/ui/coroutine/not-send-sync.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be shared between threads safely --> $DIR/not-send-sync.rs:14:5 | -LL | / assert_sync(|| { +LL | / assert_sync(#[coroutine] || { LL | | LL | | let a = NotSync; LL | | yield; @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}: Sync` + = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}: Sync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:17:9 | @@ -26,7 +26,7 @@ LL | fn assert_sync(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/not-send-sync.rs:21:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | LL | | let a = NotSend; LL | | yield; @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}: Send` + = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/not-send-sync.rs:24:9 | diff --git a/tests/ui/coroutine/overlap-locals.rs b/tests/ui/coroutine/overlap-locals.rs index eea8595ed06fc..9cfa6e2a76dd2 100644 --- a/tests/ui/coroutine/overlap-locals.rs +++ b/tests/ui/coroutine/overlap-locals.rs @@ -1,9 +1,10 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let a = || { + let a = #[coroutine] + || { { let w: i32 = 4; yield; diff --git a/tests/ui/coroutine/panic-drops-resume.rs b/tests/ui/coroutine/panic-drops-resume.rs index 6d026e6edc8ac..b23666b7885fb 100644 --- a/tests/ui/coroutine/panic-drops-resume.rs +++ b/tests/ui/coroutine/panic-drops-resume.rs @@ -3,7 +3,7 @@ //@ run-pass //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -21,7 +21,7 @@ impl Drop for Dropper { } fn main() { - let mut gen = |_arg| { + let mut gen = #[coroutine] |_arg| { if true { panic!(); } diff --git a/tests/ui/coroutine/panic-drops.rs b/tests/ui/coroutine/panic-drops.rs index c99abdc72461c..8c2cf560f2acc 100644 --- a/tests/ui/coroutine/panic-drops.rs +++ b/tests/ui/coroutine/panic-drops.rs @@ -1,8 +1,7 @@ //@ run-pass //@ needs-unwind - -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::panic; @@ -25,7 +24,8 @@ fn bool_true() -> bool { fn main() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] + || { if bool_true() { panic!(); } @@ -34,13 +34,12 @@ fn main() { }; assert_eq!(A.load(Ordering::SeqCst), 0); - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - Pin::new(&mut foo).resume(()) - })); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Pin::new(&mut foo).resume(()))); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); - let mut foo = || { + let mut foo = #[coroutine] + || { if bool_true() { panic!(); } @@ -49,9 +48,7 @@ fn main() { }; assert_eq!(A.load(Ordering::SeqCst), 1); - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - Pin::new(&mut foo).resume(()) - })); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Pin::new(&mut foo).resume(()))); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); } diff --git a/tests/ui/coroutine/panic-safe.rs b/tests/ui/coroutine/panic-safe.rs index 89dd09bf5203b..6b9b4cb33c322 100644 --- a/tests/ui/coroutine/panic-safe.rs +++ b/tests/ui/coroutine/panic-safe.rs @@ -2,14 +2,14 @@ //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; use std::panic; fn main() { - let mut foo = || { + let mut foo = #[coroutine] || { if true { panic!(); } diff --git a/tests/ui/coroutine/parent-expression.rs b/tests/ui/coroutine/parent-expression.rs index 4d40192c07a27..0f4d99c893648 100644 --- a/tests/ui/coroutine/parent-expression.rs +++ b/tests/ui/coroutine/parent-expression.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, negative_impls, rustc_attrs)] +#![feature(coroutines, negative_impls, rustc_attrs, stmt_expr_attributes)] macro_rules! type_combinations { ( @@ -14,7 +14,7 @@ macro_rules! type_combinations { // Struct update syntax. This fails because the Client used in the update is considered // dropped *after* the yield. { - let g = move || match drop($name::Client { ..$name::Client::default() }) { + let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { //~^ `significant_drop::Client` which is not `Send` //~| `insignificant_dtor::Client` which is not `Send` //~| `derived_drop::Client` which is not `Send` @@ -29,7 +29,7 @@ macro_rules! type_combinations { // Simple owned value. This works because the Client is considered moved into `drop`, // even though the temporary expression doesn't end until after the yield. { - let g = move || match drop($name::Client::default()) { + let g = #[coroutine] move || match drop($name::Client::default()) { _ => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr index 5b3737069e6c1..2d817f1bfd9cb 100644 --- a/tests/ui/coroutine/parent-expression.stderr +++ b/tests/ui/coroutine/parent-expression.stderr @@ -13,12 +13,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -53,12 +53,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -93,12 +93,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later diff --git a/tests/ui/coroutine/partial-drop.rs b/tests/ui/coroutine/partial-drop.rs index ba13544712f13..9efb551c9c181 100644 --- a/tests/ui/coroutine/partial-drop.rs +++ b/tests/ui/coroutine/partial-drop.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo; impl !Send for Foo {} @@ -10,25 +10,34 @@ struct Bar { } fn main() { - assert_send(|| { - let guard = Bar { foo: Foo, x: 42 }; - drop(guard.foo); - yield; - }); + assert_send( + #[coroutine] + || { + let guard = Bar { foo: Foo, x: 42 }; + drop(guard.foo); + yield; + }, + ); - assert_send(|| { - let mut guard = Bar { foo: Foo, x: 42 }; - drop(guard); - guard = Bar { foo: Foo, x: 23 }; - yield; - }); + assert_send( + #[coroutine] + || { + let mut guard = Bar { foo: Foo, x: 42 }; + drop(guard); + guard = Bar { foo: Foo, x: 23 }; + yield; + }, + ); - assert_send(|| { - let guard = Bar { foo: Foo, x: 42 }; - let Bar { foo, x } = guard; - drop(foo); - yield; - }); + assert_send( + #[coroutine] + || { + let guard = Bar { foo: Foo, x: 42 }; + let Bar { foo, x } = guard; + drop(foo); + yield; + }, + ); } fn assert_send(_: T) {} diff --git a/tests/ui/coroutine/partial-initialization-across-yield.rs b/tests/ui/coroutine/partial-initialization-across-yield.rs index 75ad5a2280403..ab6f9c5b1e981 100644 --- a/tests/ui/coroutine/partial-initialization-across-yield.rs +++ b/tests/ui/coroutine/partial-initialization-across-yield.rs @@ -1,13 +1,13 @@ // Test that we don't allow yielding from a coroutine while a local is partially // initialized. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] struct S { x: i32, y: i32 } struct T(i32, i32); fn test_tuple() { - let _ = || { + let _ = #[coroutine] || { let mut t: (i32, i32); t.0 = 42; //~ ERROR E0381 yield; @@ -17,7 +17,7 @@ fn test_tuple() { } fn test_tuple_struct() { - let _ = || { + let _ = #[coroutine] || { let mut t: T; t.0 = 42; //~ ERROR E0381 yield; @@ -27,7 +27,7 @@ fn test_tuple_struct() { } fn test_struct() { - let _ = || { + let _ = #[coroutine] || { let mut t: S; t.x = 42; //~ ERROR E0381 yield; diff --git a/tests/ui/coroutine/pattern-borrow.rs b/tests/ui/coroutine/pattern-borrow.rs index 76084433d4705..46547504abc9d 100644 --- a/tests/ui/coroutine/pattern-borrow.rs +++ b/tests/ui/coroutine/pattern-borrow.rs @@ -5,7 +5,7 @@ enum Test { A(i32), B, } fn main() { } fn fun(test: Test) { - move || { + #[coroutine] move || { if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when coroutine yields yield (); _a.use_ref(); diff --git a/tests/ui/coroutine/pin-box-coroutine.rs b/tests/ui/coroutine/pin-box-coroutine.rs index 1ee6393d1d83a..d030f3ef214d1 100644 --- a/tests/ui/coroutine/pin-box-coroutine.rs +++ b/tests/ui/coroutine/pin-box-coroutine.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -8,6 +8,6 @@ fn assert_coroutine(_: G) { } fn main() { - assert_coroutine(static || yield); - assert_coroutine(Box::pin(static || yield)); + assert_coroutine(#[coroutine] static || yield); + assert_coroutine(Box::pin(#[coroutine] static || yield)); } diff --git a/tests/ui/coroutine/polymorphize-args.rs b/tests/ui/coroutine/polymorphize-args.rs index 21aa3c7aafd8c..5123bf412b553 100644 --- a/tests/ui/coroutine/polymorphize-args.rs +++ b/tests/ui/coroutine/polymorphize-args.rs @@ -1,14 +1,15 @@ //@ compile-flags: -Zpolymorphize=on //@ build-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; use std::thread; fn main() { - let mut foo = || yield; + let mut foo = #[coroutine] + || yield; thread::spawn(move || match Pin::new(&mut foo).resume(()) { s => panic!("bad state: {:?}", s), }) diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.rs b/tests/ui/coroutine/print/coroutine-print-verbose-1.rs index 73106328618ea..dc0165c9194da 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.rs @@ -2,7 +2,7 @@ // Same as: tests/ui/coroutine/issue-68112.stderr -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ cell::RefCell, @@ -30,7 +30,7 @@ fn make_non_send_coroutine() -> impl Coroutine>> { } fn test1() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine(); yield; }; @@ -39,7 +39,7 @@ fn test1() { } pub fn make_gen2(t: T) -> impl Coroutine { - || { + #[coroutine] || { yield; t } @@ -49,7 +49,7 @@ fn make_non_send_coroutine2() -> impl Coroutine>> { } fn test2() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine2(); yield; }; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr index 37db83d57f756..934ab08cf178d 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr @@ -29,10 +29,10 @@ LL | require_send(send_gen); = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this coroutine - --> $DIR/coroutine-print-verbose-1.rs:42:5 + --> $DIR/coroutine-print-verbose-1.rs:42:18 | -LL | || { - | ^^ +LL | #[coroutine] || { + | ^^ note: required because it appears within the type `Opaque(DefId(0:35 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc>])` --> $DIR/coroutine-print-verbose-1.rs:41:30 | @@ -44,10 +44,10 @@ note: required because it appears within the type `Opaque(DefId(0:36 ~ coroutine LL | fn make_non_send_coroutine2() -> impl Coroutine>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it's used within this coroutine - --> $DIR/coroutine-print-verbose-1.rs:52:20 + --> $DIR/coroutine-print-verbose-1.rs:52:33 | -LL | let send_gen = || { - | ^^ +LL | let send_gen = #[coroutine] || { + | ^^ note: required by a bound in `require_send` --> $DIR/coroutine-print-verbose-1.rs:26:25 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.rs b/tests/ui/coroutine/print/coroutine-print-verbose-2.rs index f9ea68a8cd942..ef7199cafdde0 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Zverbose-internals // Same as test/ui/coroutine/not-send-sync.rs -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(negative_impls)] struct NotSend; @@ -14,14 +14,14 @@ fn main() { fn assert_sync(_: T) {} fn assert_send(_: T) {} - assert_sync(|| { + assert_sync(#[coroutine] || { //~^ ERROR: coroutine cannot be shared between threads safely let a = NotSync; yield; drop(a); }); - assert_send(|| { + assert_send(#[coroutine] || { //~^ ERROR: coroutine cannot be sent between threads safely let a = NotSend; yield; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 26c9c27743c01..0de53d9e1d7d5 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be shared between threads safely --> $DIR/coroutine-print-verbose-2.rs:17:5 | -LL | / assert_sync(|| { +LL | / assert_sync(#[coroutine] || { LL | | LL | | let a = NotSync; LL | | yield; @@ -26,7 +26,7 @@ LL | fn assert_sync(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/coroutine-print-verbose-2.rs:24:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | LL | | let a = NotSend; LL | | yield; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.rs b/tests/ui/coroutine/print/coroutine-print-verbose-3.rs index be6dbad9e1c2b..5dd15fc1b9516 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.rs @@ -1,12 +1,13 @@ //@ compile-flags: -Zverbose-internals -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { let x = "Type mismatch test"; - let coroutine :() = || { - //~^ ERROR mismatched types + let coroutine: () = #[coroutine] + || { + //~^ ERROR mismatched types yield 1i32; - return x + return x; }; } diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index e2973cde6d3cc..dce45aeae56a9 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -1,13 +1,12 @@ error[E0308]: mismatched types - --> $DIR/coroutine-print-verbose-3.rs:7:25 + --> $DIR/coroutine-print-verbose-3.rs:8:5 | -LL | let coroutine :() = || { - | ____________________--___^ - | | | - | | expected due to this +LL | let coroutine: () = #[coroutine] + | -- expected due to this +LL | / || { LL | | LL | | yield 1i32; -LL | | return x +LL | | return x; LL | | }; | |_____^ expected `()`, found coroutine | diff --git a/tests/ui/coroutine/reborrow-mut-upvar.rs b/tests/ui/coroutine/reborrow-mut-upvar.rs index e1f6211baebda..716781e365c5a 100644 --- a/tests/ui/coroutine/reborrow-mut-upvar.rs +++ b/tests/ui/coroutine/reborrow-mut-upvar.rs @@ -3,7 +3,7 @@ #![feature(coroutines)] fn _run(bar: &mut i32) { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used { let _baz = &*bar; yield; diff --git a/tests/ui/coroutine/reborrow-mut-upvar.stderr b/tests/ui/coroutine/reborrow-mut-upvar.stderr index 5b614ac4be8b2..a05e84c5f3ef2 100644 --- a/tests/ui/coroutine/reborrow-mut-upvar.stderr +++ b/tests/ui/coroutine/reborrow-mut-upvar.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/reborrow-mut-upvar.rs:6:5 + --> $DIR/reborrow-mut-upvar.rs:6:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | { LL | | let _baz = &*bar; LL | | yield; diff --git a/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs b/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs index a9c13188ff386..0f9c56786da06 100644 --- a/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs +++ b/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs @@ -1,16 +1,17 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo(x: &i32) { // In this case, a reference to `b` escapes the coroutine, but not // because of a yield. We see that there is no yield in the scope of // `b` and give the more generic error message. let mut a = &3; - let mut b = move || { - yield(); + let mut b = #[coroutine] + move || { + yield (); let b = 5; a = &b; //~^ ERROR borrowed data escapes outside of coroutine }; } -fn main() { } +fn main() {} diff --git a/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr b/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr index 8811faf2fade5..6fa7082c0b8b7 100644 --- a/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr +++ b/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr @@ -1,5 +1,5 @@ error[E0521]: borrowed data escapes outside of coroutine - --> $DIR/ref-escapes-but-not-over-yield.rs:11:9 + --> $DIR/ref-escapes-but-not-over-yield.rs:12:9 | LL | let mut a = &3; | ----- `a` declared here, outside of the coroutine body diff --git a/tests/ui/coroutine/ref-upvar-not-send.rs b/tests/ui/coroutine/ref-upvar-not-send.rs index 487fdeea2dae9..89bb5e5495f45 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.rs +++ b/tests/ui/coroutine/ref-upvar-not-send.rs @@ -1,7 +1,7 @@ // For `Send` coroutines, suggest a `T: Sync` requirement for `&T` upvars, // and suggest a `T: Send` requirement for `&mut T` upvars. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn assert_send(_: T) {} //~^ NOTE required by a bound in `assert_send` @@ -12,7 +12,7 @@ fn assert_send(_: T) {} fn main() { let x: &*mut () = &std::ptr::null_mut(); let y: &mut *mut () = &mut std::ptr::null_mut(); - assert_send(move || { + assert_send(#[coroutine] move || { //~^ ERROR coroutine cannot be sent between threads safely //~| NOTE coroutine is not `Send` yield; @@ -20,7 +20,7 @@ fn main() { }); //~^^ NOTE captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` //~| NOTE has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync` - assert_send(move || { + assert_send(#[coroutine] move || { //~^ ERROR coroutine cannot be sent between threads safely //~| NOTE coroutine is not `Send` yield; diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 0f91bcf40533f..4c7deab3f4c4d 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -1,8 +1,8 @@ error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:15:17 + --> $DIR/ref-upvar-not-send.rs:15:30 | -LL | assert_send(move || { - | _________________^ +LL | assert_send(#[coroutine] move || { + | ______________________________^ LL | | LL | | LL | | yield; @@ -10,7 +10,7 @@ LL | | let _x = x; LL | | }); | |_____^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:17: 15:24}: Send` + = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:30: 15:37}: Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> $DIR/ref-upvar-not-send.rs:19:18 | @@ -23,10 +23,10 @@ LL | fn assert_send(_: T) {} | ^^^^ required by this bound in `assert_send` error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:23:17 + --> $DIR/ref-upvar-not-send.rs:23:30 | -LL | assert_send(move || { - | _________________^ +LL | assert_send(#[coroutine] move || { + | ______________________________^ LL | | LL | | LL | | yield; @@ -34,7 +34,7 @@ LL | | let _y = y; LL | | }); | |_____^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}: Send` + = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}: Send` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` --> $DIR/ref-upvar-not-send.rs:27:18 | diff --git a/tests/ui/coroutine/reinit-in-match-guard.rs b/tests/ui/coroutine/reinit-in-match-guard.rs index 4a58420477314..0a97d9fbcb2f7 100644 --- a/tests/ui/coroutine/reinit-in-match-guard.rs +++ b/tests/ui/coroutine/reinit-in-match-guard.rs @@ -1,11 +1,11 @@ //@ build-pass -#![feature(coroutines)] - +#![feature(coroutines, stmt_expr_attributes)] #![allow(unused_assignments, dead_code)] fn main() { - let _ = || { + let _ = #[coroutine] + || { let mut x = vec![22_usize]; std::mem::drop(x); match y() { diff --git a/tests/ui/coroutine/resume-after-return.rs b/tests/ui/coroutine/resume-after-return.rs index 81f86de641f25..7028e1e81e55c 100644 --- a/tests/ui/coroutine/resume-after-return.rs +++ b/tests/ui/coroutine/resume-after-return.rs @@ -1,17 +1,17 @@ //@ run-pass //@ needs-unwind +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -#![feature(coroutines, coroutine_trait)] - -use std::ops::{CoroutineState, Coroutine}; -use std::pin::Pin; +use std::ops::{Coroutine, CoroutineState}; use std::panic; +use std::pin::Pin; fn main() { - let mut foo = || { + let mut foo = #[coroutine] + || { if true { - return + return; } yield; }; diff --git a/tests/ui/coroutine/resume-arg-late-bound.rs b/tests/ui/coroutine/resume-arg-late-bound.rs index 3c2ab41047e3d..e84184da631b5 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.rs +++ b/tests/ui/coroutine/resume-arg-late-bound.rs @@ -1,14 +1,14 @@ //! Tests that we cannot produce a coroutine that accepts a resume argument //! with any lifetime and then stores it across a `yield`. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; fn test(a: impl for<'a> Coroutine<&'a mut bool>) {} fn main() { - let gen = |arg: &mut bool| { + let gen = #[coroutine] |arg: &mut bool| { yield (); *arg = true; }; diff --git a/tests/ui/coroutine/resume-arg-late-bound.stderr b/tests/ui/coroutine/resume-arg-late-bound.stderr index 4a4ee08c529ec..646abaf4f7bde 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.stderr +++ b/tests/ui/coroutine/resume-arg-late-bound.stderr @@ -4,7 +4,7 @@ error: implementation of `Coroutine` is not general enough LL | test(gen); | ^^^^^^^^^ implementation of `Coroutine` is not general enough | - = note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:15: 11:31}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... + = note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:28: 11:44}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... = note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/resume-arg-size.rs b/tests/ui/coroutine/resume-arg-size.rs index 81e96975c98f6..59740a28f428a 100644 --- a/tests/ui/coroutine/resume-arg-size.rs +++ b/tests/ui/coroutine/resume-arg-size.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(dropping_copy_types)] //@ run-pass @@ -7,7 +7,8 @@ use std::mem::size_of_val; fn main() { // Coroutine taking a `Copy`able resume arg. - let gen_copy = |mut x: usize| { + let gen_copy = #[coroutine] + |mut x: usize| { loop { drop(x); x = yield; @@ -15,7 +16,8 @@ fn main() { }; // Coroutine taking a non-`Copy` resume arg. - let gen_move = |mut x: Box| { + let gen_move = #[coroutine] + |mut x: Box| { loop { drop(x); x = yield; diff --git a/tests/ui/coroutine/resume-live-across-yield.rs b/tests/ui/coroutine/resume-live-across-yield.rs index 45851411daaac..b67619ee70fb2 100644 --- a/tests/ui/coroutine/resume-live-across-yield.rs +++ b/tests/ui/coroutine/resume-live-across-yield.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -18,7 +18,8 @@ impl Drop for Dropper { } fn main() { - let mut g = |mut _d| { + let mut g = #[coroutine] + |mut _d| { _d = yield; _d }; diff --git a/tests/ui/coroutine/retain-resume-ref.rs b/tests/ui/coroutine/retain-resume-ref.rs index c9f995ab0cf31..6e688c33979ac 100644 --- a/tests/ui/coroutine/retain-resume-ref.rs +++ b/tests/ui/coroutine/retain-resume-ref.rs @@ -1,6 +1,6 @@ //! This test ensures that a mutable reference cannot be passed as a resume argument twice. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::marker::Unpin; use std::ops::{ @@ -12,7 +12,8 @@ use std::pin::Pin; fn main() { let mut thing = String::from("hello"); - let mut gen = |r| { + let mut gen = #[coroutine] + |r| { if false { yield r; } diff --git a/tests/ui/coroutine/retain-resume-ref.stderr b/tests/ui/coroutine/retain-resume-ref.stderr index eb8b78df6c998..e23023c6e23f3 100644 --- a/tests/ui/coroutine/retain-resume-ref.stderr +++ b/tests/ui/coroutine/retain-resume-ref.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `thing` as mutable more than once at a time - --> $DIR/retain-resume-ref.rs:23:25 + --> $DIR/retain-resume-ref.rs:24:25 | LL | gen.as_mut().resume(&mut thing); | ---------- first mutable borrow occurs here diff --git a/tests/ui/coroutine/size-moved-locals.rs b/tests/ui/coroutine/size-moved-locals.rs index eb5210087a0e6..0f800de84544d 100644 --- a/tests/ui/coroutine/size-moved-locals.rs +++ b/tests/ui/coroutine/size-moved-locals.rs @@ -24,6 +24,7 @@ impl Drop for Foo { } fn move_before_yield() -> impl Coroutine { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); let _second = first; @@ -35,6 +36,7 @@ fn move_before_yield() -> impl Coroutine { fn noop() {} fn move_before_yield_with_noop() -> impl Coroutine { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); noop(); @@ -47,6 +49,7 @@ fn move_before_yield_with_noop() -> impl Coroutine { // Today we don't have NRVO (we allocate space for both `first` and `second`,) // but we can overlap `first` with `_third`. fn overlap_move_points() -> impl Coroutine { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); yield; @@ -58,6 +61,7 @@ fn overlap_move_points() -> impl Coroutine { } fn overlap_x_and_y() -> impl Coroutine { + #[coroutine] static || { let x = Foo([0; FOO_SIZE]); yield; diff --git a/tests/ui/coroutine/sized-yield.rs b/tests/ui/coroutine/sized-yield.rs index 1368c88b5227d..a4c91fafe6ca5 100644 --- a/tests/ui/coroutine/sized-yield.rs +++ b/tests/ui/coroutine/sized-yield.rs @@ -1,11 +1,12 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let s = String::from("foo"); - let mut gen = move || { + let mut gen = #[coroutine] + move || { //~^ ERROR the size for values of type yield s[..]; }; diff --git a/tests/ui/coroutine/sized-yield.stderr b/tests/ui/coroutine/sized-yield.stderr index 4e8dc13201de3..5d5dd6803c899 100644 --- a/tests/ui/coroutine/sized-yield.stderr +++ b/tests/ui/coroutine/sized-yield.stderr @@ -1,8 +1,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/sized-yield.rs:8:19 + --> $DIR/sized-yield.rs:9:5 | -LL | let mut gen = move || { - | ___________________^ +LL | / move || { LL | | LL | | yield s[..]; LL | | }; @@ -12,7 +11,7 @@ LL | | }; = note: the yield type of a coroutine must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/sized-yield.rs:12:24 + --> $DIR/sized-yield.rs:13:24 | LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/coroutine/smoke-resume-args.rs b/tests/ui/coroutine/smoke-resume-args.rs index 7d20cd2293d6b..209c481400189 100644 --- a/tests/ui/coroutine/smoke-resume-args.rs +++ b/tests/ui/coroutine/smoke-resume-args.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::fmt::Debug; use std::ops::{ @@ -50,7 +50,7 @@ fn expect_drops(expected_drops: usize, f: impl FnOnce() -> T) -> T { fn main() { drain( - &mut |mut b| { + &mut #[coroutine] |mut b| { while b != 0 { b = yield (b + 1); } @@ -59,21 +59,24 @@ fn main() { vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], ); - expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + expect_drops(2, || drain(&mut #[coroutine] |a| yield a, vec![(DropMe, Yielded(DropMe))])); expect_drops(6, || { drain( - &mut |a| yield yield a, + &mut #[coroutine] |a| yield yield a, vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], ) }); #[allow(unreachable_code)] - expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + expect_drops(2, || drain( + &mut #[coroutine] |a| yield return a, + vec![(DropMe, Complete(DropMe))] + )); expect_drops(2, || { drain( - &mut |a: DropMe| { + &mut #[coroutine] |a: DropMe| { if false { yield () } else { a } }, vec![(DropMe, Complete(DropMe))], @@ -83,7 +86,7 @@ fn main() { expect_drops(4, || { drain( #[allow(unused_assignments, unused_variables)] - &mut |mut a: DropMe| { + &mut #[coroutine] |mut a: DropMe| { a = yield; a = yield; a = yield; diff --git a/tests/ui/coroutine/smoke.rs b/tests/ui/coroutine/smoke.rs index 17d98a52a1c49..bfb183fde9368 100644 --- a/tests/ui/coroutine/smoke.rs +++ b/tests/ui/coroutine/smoke.rs @@ -6,7 +6,7 @@ //@ needs-threads //@ compile-flags: --test -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; @@ -14,7 +14,7 @@ use std::thread; #[test] fn simple() { - let mut foo = || { + let mut foo = #[coroutine] || { if false { yield; } @@ -29,7 +29,7 @@ fn simple() { #[test] fn return_capture() { let a = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { if false { yield; } @@ -44,7 +44,7 @@ fn return_capture() { #[test] fn simple_yield() { - let mut foo = || { + let mut foo = #[coroutine] || { yield; }; @@ -61,7 +61,7 @@ fn simple_yield() { #[test] fn yield_capture() { let b = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { yield b; }; @@ -77,7 +77,7 @@ fn yield_capture() { #[test] fn simple_yield_value() { - let mut foo = || { + let mut foo = #[coroutine] || { yield String::from("bar"); return String::from("foo") }; @@ -95,7 +95,7 @@ fn simple_yield_value() { #[test] fn return_after_yield() { let a = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { yield; return a }; @@ -112,34 +112,34 @@ fn return_after_yield() { #[test] fn send_and_sync() { - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield }); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield String::from("foo"); }); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield; return String::from("foo"); }); let a = 3; - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield a; return }); let a = 3; - assert_send_sync(move || { + assert_send_sync(#[coroutine] move || { yield a; return }); let a = String::from("a"); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield ; drop(a); return }); let a = String::from("a"); - assert_send_sync(move || { + assert_send_sync(#[coroutine] move || { yield ; drop(a); return @@ -150,7 +150,7 @@ fn send_and_sync() { #[test] fn send_over_threads() { - let mut foo = || { yield }; + let mut foo = #[coroutine] || { yield }; thread::spawn(move || { match Pin::new(&mut foo).resume(()) { CoroutineState::Yielded(()) => {} @@ -163,7 +163,7 @@ fn send_over_threads() { }).join().unwrap(); let a = String::from("a"); - let mut foo = || { yield a }; + let mut foo = #[coroutine] || { yield a }; thread::spawn(move || { match Pin::new(&mut foo).resume(()) { CoroutineState::Yielded(ref s) if *s == "a" => {} diff --git a/tests/ui/coroutine/static-coroutine.rs b/tests/ui/coroutine/static-coroutine.rs index 9beaef3e4de31..eba6336d342fe 100644 --- a/tests/ui/coroutine/static-coroutine.rs +++ b/tests/ui/coroutine/static-coroutine.rs @@ -1,12 +1,13 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::pin::Pin; use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; fn main() { - let mut coroutine = static || { + let mut coroutine = #[coroutine] + static || { let a = true; let b = &a; yield; diff --git a/tests/ui/coroutine/static-mut-reference-across-yield.rs b/tests/ui/coroutine/static-mut-reference-across-yield.rs index 0d8042ed8526b..40d5fdf2d5736 100644 --- a/tests/ui/coroutine/static-mut-reference-across-yield.rs +++ b/tests/ui/coroutine/static-mut-reference-across-yield.rs @@ -1,6 +1,6 @@ //@ build-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; @@ -8,13 +8,15 @@ fn is_send_sync(_: T) {} fn main() { unsafe { - let gen_index = static || { + let gen_index = #[coroutine] + static || { let u = A[{ yield; 1 }]; }; - let gen_match = static || match A { + let gen_match = #[coroutine] + static || match A { i if { yield; true diff --git a/tests/ui/coroutine/static-not-unpin.current.stderr b/tests/ui/coroutine/static-not-unpin.current.stderr index 518abdd62c790..7d6260ac569e8 100644 --- a/tests/ui/coroutine/static-not-unpin.current.stderr +++ b/tests/ui/coroutine/static-not-unpin.current.stderr @@ -1,8 +1,8 @@ -error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` cannot be unpinned +error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned --> $DIR/static-not-unpin.rs:18:18 | LL | assert_unpin(coroutine); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` | | | required by a bound introduced by this call | @@ -11,7 +11,7 @@ LL | assert_unpin(coroutine); note: required by a bound in `assert_unpin` --> $DIR/static-not-unpin.rs:11:20 | -LL | fn assert_unpin(_: T) { +LL | fn assert_unpin(_: T) {} | ^^^^^ required by this bound in `assert_unpin` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/static-not-unpin.next.stderr b/tests/ui/coroutine/static-not-unpin.next.stderr index 518abdd62c790..7d6260ac569e8 100644 --- a/tests/ui/coroutine/static-not-unpin.next.stderr +++ b/tests/ui/coroutine/static-not-unpin.next.stderr @@ -1,8 +1,8 @@ -error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` cannot be unpinned +error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned --> $DIR/static-not-unpin.rs:18:18 | LL | assert_unpin(coroutine); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` | | | required by a bound introduced by this call | @@ -11,7 +11,7 @@ LL | assert_unpin(coroutine); note: required by a bound in `assert_unpin` --> $DIR/static-not-unpin.rs:11:20 | -LL | fn assert_unpin(_: T) { +LL | fn assert_unpin(_: T) {} | ^^^^^ required by this bound in `assert_unpin` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/static-not-unpin.rs b/tests/ui/coroutine/static-not-unpin.rs index 3704cca772977..2bc25e3796d45 100644 --- a/tests/ui/coroutine/static-not-unpin.rs +++ b/tests/ui/coroutine/static-not-unpin.rs @@ -2,17 +2,17 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] //@ normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin" use std::marker::Unpin; -fn assert_unpin(_: T) { -} +fn assert_unpin(_: T) {} fn main() { - let mut coroutine = static || { + let mut coroutine = #[coroutine] + static || { yield; }; assert_unpin(coroutine); //~ ERROR E0277 diff --git a/tests/ui/coroutine/static-reference-across-yield.rs b/tests/ui/coroutine/static-reference-across-yield.rs index cf19ccb54d535..e7ff658ebf643 100644 --- a/tests/ui/coroutine/static-reference-across-yield.rs +++ b/tests/ui/coroutine/static-reference-across-yield.rs @@ -4,10 +4,10 @@ static A: [i32; 5] = [1, 2, 3, 4, 5]; fn main() { - static || { + #[coroutine] static || { let u = A[{yield; 1}]; }; - static || { + #[coroutine] static || { match A { i if { yield; true } => (), _ => (), diff --git a/tests/ui/coroutine/too-live-local-in-immovable-gen.rs b/tests/ui/coroutine/too-live-local-in-immovable-gen.rs index 382e7ff38143d..1c689ef7cefc4 100644 --- a/tests/ui/coroutine/too-live-local-in-immovable-gen.rs +++ b/tests/ui/coroutine/too-live-local-in-immovable-gen.rs @@ -5,7 +5,7 @@ fn main() { unsafe { - static move || { //~ WARN unused coroutine that must be used + #[coroutine] static move || { //~ WARN unused coroutine that must be used // Tests that the coroutine transformation finds out that `a` is not live // during the yield expression. Type checking will also compute liveness // and it should also find out that `a` is not live. diff --git a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr index 4a67dbe71e19b..48df5c5beacd7 100644 --- a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr +++ b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/too-live-local-in-immovable-gen.rs:8:9 + --> $DIR/too-live-local-in-immovable-gen.rs:8:22 | -LL | / static move || { +LL | #[coroutine] static move || { + | ______________________^ LL | | // Tests that the coroutine transformation finds out that `a` is not live LL | | // during the yield expression. Type checking will also compute liveness LL | | // and it should also find out that `a` is not live. diff --git a/tests/ui/coroutine/too-many-parameters.rs b/tests/ui/coroutine/too-many-parameters.rs index 377d80c7b22e2..3baaf0623479d 100644 --- a/tests/ui/coroutine/too-many-parameters.rs +++ b/tests/ui/coroutine/too-many-parameters.rs @@ -1,6 +1,7 @@ #![feature(coroutines)] fn main() { + #[coroutine] |(), ()| { //~^ error: too many parameters for a coroutine yield; diff --git a/tests/ui/coroutine/too-many-parameters.stderr b/tests/ui/coroutine/too-many-parameters.stderr index c0917c7225ba4..45dad8e349e25 100644 --- a/tests/ui/coroutine/too-many-parameters.stderr +++ b/tests/ui/coroutine/too-many-parameters.stderr @@ -1,5 +1,5 @@ error[E0628]: too many parameters for a coroutine (expected 0 or 1 parameters) - --> $DIR/too-many-parameters.rs:4:5 + --> $DIR/too-many-parameters.rs:5:5 | LL | |(), ()| { | ^^^^^^^^ diff --git a/tests/ui/coroutine/type-mismatch-error.rs b/tests/ui/coroutine/type-mismatch-error.rs index 0d04c21484cbe..ee4e27c20da18 100644 --- a/tests/ui/coroutine/type-mismatch-error.rs +++ b/tests/ui/coroutine/type-mismatch-error.rs @@ -1,7 +1,7 @@ //! Test that we get the expected type mismatch error instead of "closure is expected to take 0 //! arguments" (which got introduced after implementing resume arguments). -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -9,6 +9,7 @@ fn f(_: G, _: G::Return) {} fn main() { f( + #[coroutine] |a: u8| { if false { yield (); diff --git a/tests/ui/coroutine/type-mismatch-error.stderr b/tests/ui/coroutine/type-mismatch-error.stderr index 737d9afdd79a9..f10c30e259072 100644 --- a/tests/ui/coroutine/type-mismatch-error.stderr +++ b/tests/ui/coroutine/type-mismatch-error.stderr @@ -1,5 +1,5 @@ error[E0308]: `if` and `else` have incompatible types - --> $DIR/type-mismatch-error.rs:16:17 + --> $DIR/type-mismatch-error.rs:17:17 | LL | / if false { LL | | yield (); diff --git a/tests/ui/coroutine/type-mismatch-signature-deduction.rs b/tests/ui/coroutine/type-mismatch-signature-deduction.rs index d4ca622e80f53..5b04b3efaaa46 100644 --- a/tests/ui/coroutine/type-mismatch-signature-deduction.rs +++ b/tests/ui/coroutine/type-mismatch-signature-deduction.rs @@ -4,6 +4,7 @@ use std::ops::Coroutine; fn foo() -> impl Coroutine { //~^ ERROR type mismatch + #[coroutine] || { if false { return Ok(6); diff --git a/tests/ui/coroutine/type-mismatch-signature-deduction.stderr b/tests/ui/coroutine/type-mismatch-signature-deduction.stderr index f26e30a8e7435..0892719603752 100644 --- a/tests/ui/coroutine/type-mismatch-signature-deduction.stderr +++ b/tests/ui/coroutine/type-mismatch-signature-deduction.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/type-mismatch-signature-deduction.rs:14:9 + --> $DIR/type-mismatch-signature-deduction.rs:15:9 | LL | 5 | ^ expected `Result<{integer}, _>`, found integer @@ -7,7 +7,7 @@ LL | 5 = note: expected enum `Result<{integer}, _>` found type `{integer}` note: return type inferred to be `Result<{integer}, _>` here - --> $DIR/type-mismatch-signature-deduction.rs:9:20 + --> $DIR/type-mismatch-signature-deduction.rs:10:20 | LL | return Ok(6); | ^^^^^ @@ -18,7 +18,7 @@ LL | Ok(5) LL | Err(5) | ++++ + -error[E0271]: type mismatch resolving `<{coroutine@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7} as Coroutine>::Return == i32` +error[E0271]: type mismatch resolving `<{coroutine@$DIR/type-mismatch-signature-deduction.rs:8:5: 8:7} as Coroutine>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Coroutine { diff --git a/tests/ui/coroutine/uninhabited-field.rs b/tests/ui/coroutine/uninhabited-field.rs index 79776d653b1f7..d6ada07ce0cbc 100644 --- a/tests/ui/coroutine/uninhabited-field.rs +++ b/tests/ui/coroutine/uninhabited-field.rs @@ -3,7 +3,7 @@ #![allow(unused)] #![feature(assert_matches)] #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(never_type)] use std::assert_matches::assert_matches; use std::ops::Coroutine; @@ -13,7 +13,7 @@ use std::pin::Pin; fn conjure() -> T { loop {} } fn run(x: bool, y: bool) { - let mut c = || { + let mut c = #[coroutine] || { if x { let a : T; if y { diff --git a/tests/ui/coroutine/unsized-capture-across-yield.rs b/tests/ui/coroutine/unsized-capture-across-yield.rs index ef9cbc1d677da..c86b1823aafff 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.rs +++ b/tests/ui/coroutine/unsized-capture-across-yield.rs @@ -7,6 +7,7 @@ use std::ops::Coroutine; fn capture() -> impl Coroutine { let b: [u8] = *(Box::new([]) as Box<[u8]>); + #[coroutine] move || { println!("{:?}", &b); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/coroutine/unsized-capture-across-yield.stderr b/tests/ui/coroutine/unsized-capture-across-yield.stderr index 436f0901a9776..03551f1bbff51 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.stderr +++ b/tests/ui/coroutine/unsized-capture-across-yield.stderr @@ -8,7 +8,7 @@ LL | #![feature(unsized_locals)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-capture-across-yield.rs:11:27 + --> $DIR/unsized-capture-across-yield.rs:12:27 | LL | move || { | -- this closure captures all values by move diff --git a/tests/ui/coroutine/unsized-local-across-yield.rs b/tests/ui/coroutine/unsized-local-across-yield.rs index 7a8ed60e46ae4..cb8ced13a111a 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.rs +++ b/tests/ui/coroutine/unsized-local-across-yield.rs @@ -6,6 +6,7 @@ use std::ops::Coroutine; fn across() -> impl Coroutine { + #[coroutine] move || { let b: [u8] = *(Box::new([]) as Box<[u8]>); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/coroutine/unsized-local-across-yield.stderr b/tests/ui/coroutine/unsized-local-across-yield.stderr index c4c3be77ac2bd..4fe0f135a9d62 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.stderr +++ b/tests/ui/coroutine/unsized-local-across-yield.stderr @@ -8,7 +8,7 @@ LL | #![feature(unsized_locals)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-local-across-yield.rs:10:13 + --> $DIR/unsized-local-across-yield.rs:11:13 | LL | let b: [u8] = *(Box::new([]) as Box<[u8]>); | ^ doesn't have a size known at compile-time diff --git a/tests/ui/coroutine/yield-in-args-rev.rs b/tests/ui/coroutine/yield-in-args-rev.rs index b074e2bc93987..29d79df25fbab 100644 --- a/tests/ui/coroutine/yield-in-args-rev.rs +++ b/tests/ui/coroutine/yield-in-args-rev.rs @@ -10,7 +10,7 @@ fn foo(_a: (), _b: &bool) {} fn bar() { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used let b = true; foo(yield, &b); }; diff --git a/tests/ui/coroutine/yield-in-args-rev.stderr b/tests/ui/coroutine/yield-in-args-rev.stderr index dbf46739e8bf1..10829d661854d 100644 --- a/tests/ui/coroutine/yield-in-args-rev.stderr +++ b/tests/ui/coroutine/yield-in-args-rev.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-in-args-rev.rs:13:5 + --> $DIR/yield-in-args-rev.rs:13:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let b = true; LL | | foo(yield, &b); LL | | }; diff --git a/tests/ui/coroutine/yield-in-args.rs b/tests/ui/coroutine/yield-in-args.rs index b2827148d771a..bc9909b310c3f 100644 --- a/tests/ui/coroutine/yield-in-args.rs +++ b/tests/ui/coroutine/yield-in-args.rs @@ -3,6 +3,7 @@ fn foo(_b: &bool, _a: ()) {} fn main() { + #[coroutine] || { let b = true; foo(&b, yield); //~ ERROR diff --git a/tests/ui/coroutine/yield-in-args.stderr b/tests/ui/coroutine/yield-in-args.stderr index 7233f47884b7b..1d2c54f9bdbfa 100644 --- a/tests/ui/coroutine/yield-in-args.stderr +++ b/tests/ui/coroutine/yield-in-args.stderr @@ -1,5 +1,5 @@ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/yield-in-args.rs:8:13 + --> $DIR/yield-in-args.rs:9:13 | LL | foo(&b, yield); | ^^ ----- possible yield occurs here diff --git a/tests/ui/coroutine/yield-in-const.rs b/tests/ui/coroutine/yield-in-const.rs index 22651f32cf85a..dc1b30155b9ff 100644 --- a/tests/ui/coroutine/yield-in-const.rs +++ b/tests/ui/coroutine/yield-in-const.rs @@ -2,5 +2,6 @@ const A: u8 = { yield 3u8; 3u8}; //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in fn main() {} diff --git a/tests/ui/coroutine/yield-in-const.stderr b/tests/ui/coroutine/yield-in-const.stderr index d5748b0533753..f02729412ccd5 100644 --- a/tests/ui/coroutine/yield-in-const.stderr +++ b/tests/ui/coroutine/yield-in-const.stderr @@ -1,9 +1,15 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-const.rs:3:17 + | +LL | const A: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-const.rs:3:17 | LL | const A: u8 = { yield 3u8; 3u8}; | ^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-in-function.rs b/tests/ui/coroutine/yield-in-function.rs index a99312043bdb9..427c5d0e7f5e5 100644 --- a/tests/ui/coroutine/yield-in-function.rs +++ b/tests/ui/coroutine/yield-in-function.rs @@ -2,3 +2,4 @@ fn main() { yield; } //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in diff --git a/tests/ui/coroutine/yield-in-function.stderr b/tests/ui/coroutine/yield-in-function.stderr index b9d4708bb8d86..dbebf310b04ff 100644 --- a/tests/ui/coroutine/yield-in-function.stderr +++ b/tests/ui/coroutine/yield-in-function.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-function.rs:3:13 + | +LL | fn main() { yield; } + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { yield; } + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-function.rs:3:13 | LL | fn main() { yield; } | ^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-in-initializer.rs b/tests/ui/coroutine/yield-in-initializer.rs index 19218926b8a0d..3caefac013ef2 100644 --- a/tests/ui/coroutine/yield-in-initializer.rs +++ b/tests/ui/coroutine/yield-in-initializer.rs @@ -3,7 +3,7 @@ #![feature(coroutines)] fn main() { - static || { //~ WARN unused coroutine that must be used + #[coroutine] static || { //~ WARN unused coroutine that must be used loop { // Test that `opt` is not live across the yield, even when borrowed in a loop // See https://github.com/rust-lang/rust/issues/52792 diff --git a/tests/ui/coroutine/yield-in-initializer.stderr b/tests/ui/coroutine/yield-in-initializer.stderr index 614df43f2f58f..1e22b7876687f 100644 --- a/tests/ui/coroutine/yield-in-initializer.stderr +++ b/tests/ui/coroutine/yield-in-initializer.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-in-initializer.rs:6:5 + --> $DIR/yield-in-initializer.rs:6:18 | -LL | / static || { +LL | #[coroutine] static || { + | __________________^ LL | | loop { LL | | // Test that `opt` is not live across the yield, even when borrowed in a loop LL | | // See https://github.com/rust-lang/rust/issues/52792 diff --git a/tests/ui/coroutine/yield-in-static.rs b/tests/ui/coroutine/yield-in-static.rs index 45e0380d46d9f..99d08913e64ce 100644 --- a/tests/ui/coroutine/yield-in-static.rs +++ b/tests/ui/coroutine/yield-in-static.rs @@ -2,5 +2,6 @@ static B: u8 = { yield 3u8; 3u8}; //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in fn main() {} diff --git a/tests/ui/coroutine/yield-in-static.stderr b/tests/ui/coroutine/yield-in-static.stderr index b56283cab6690..d1fd4eab0fc3c 100644 --- a/tests/ui/coroutine/yield-in-static.stderr +++ b/tests/ui/coroutine/yield-in-static.stderr @@ -1,9 +1,15 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-static.rs:3:18 + | +LL | static B: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-static.rs:3:18 | LL | static B: u8 = { yield 3u8; 3u8}; | ^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs index 31025c33b1a26..6833bc9901212 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs @@ -4,4 +4,5 @@ fn main() { yield || for i in 0 { } //~^ ERROR yield expression outside of coroutine literal //~| ERROR `{integer}` is not an iterator + //~| ERROR `yield` can only be used in } diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr index 8f8bec9945847..921e8d5d47a0d 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr @@ -1,3 +1,14 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-outside-coroutine-issue-78653.rs:4:5 + | +LL | yield || for i in 0 { } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-outside-coroutine-issue-78653.rs:4:5 | @@ -14,7 +25,7 @@ LL | yield || for i in 0 { } = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0627. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/yield-subtype.rs b/tests/ui/coroutine/yield-subtype.rs index 271f8362f17ed..adee5075e8324 100644 --- a/tests/ui/coroutine/yield-subtype.rs +++ b/tests/ui/coroutine/yield-subtype.rs @@ -8,7 +8,7 @@ fn bar<'a>() { let a: &'static str = "hi"; let b: &'a str = a; - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used yield a; yield b; }; diff --git a/tests/ui/coroutine/yield-subtype.stderr b/tests/ui/coroutine/yield-subtype.stderr index 5e7ae9f581eb1..973415327a5d8 100644 --- a/tests/ui/coroutine/yield-subtype.stderr +++ b/tests/ui/coroutine/yield-subtype.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-subtype.rs:11:5 + --> $DIR/yield-subtype.rs:11:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | yield a; LL | | yield b; LL | | }; diff --git a/tests/ui/coroutine/yield-while-iterating.rs b/tests/ui/coroutine/yield-while-iterating.rs index 66ac6d3922a9c..77f601e4f2c5b 100644 --- a/tests/ui/coroutine/yield-while-iterating.rs +++ b/tests/ui/coroutine/yield-while-iterating.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::cell::Cell; @@ -9,7 +9,7 @@ fn yield_during_iter_owned_data(x: Vec) { // reference to it. This winds up becoming a rather confusing // regionck error -- in particular, we would freeze with the // reference in scope, and it doesn't live long enough. - let _b = move || { + let _b =#[coroutine] move || { for p in &x { //~ ERROR yield(); } @@ -17,7 +17,7 @@ fn yield_during_iter_owned_data(x: Vec) { } fn yield_during_iter_borrowed_slice(x: &[i32]) { - let _b = move || { + let _b = #[coroutine] move || { for p in x { yield(); } @@ -26,7 +26,7 @@ fn yield_during_iter_borrowed_slice(x: &[i32]) { fn yield_during_iter_borrowed_slice_2() { let mut x = vec![22_i32]; - let _b = || { + let _b = #[coroutine] || { for p in &x { yield(); } @@ -38,7 +38,7 @@ fn yield_during_iter_borrowed_slice_3() { // OK to take a mutable ref to `x` and yield // up pointers from it: let mut x = vec![22_i32]; - let mut b = || { + let mut b = #[coroutine] || { for p in &mut x { yield p; } @@ -50,7 +50,7 @@ fn yield_during_iter_borrowed_slice_4() { // ...but not OK to do that while reading // from `x` too let mut x = vec![22_i32]; - let mut b = || { + let mut b = #[coroutine] || { for p in &mut x { yield p; } @@ -61,7 +61,7 @@ fn yield_during_iter_borrowed_slice_4() { fn yield_during_range_iter() { // Should be OK. - let mut b = || { + let mut b = #[coroutine] || { let v = vec![1,2,3]; let len = v.len(); for i in 0..len { diff --git a/tests/ui/coroutine/yield-while-iterating.stderr b/tests/ui/coroutine/yield-while-iterating.stderr index 5330121f3728f..f81c914c4bd49 100644 --- a/tests/ui/coroutine/yield-while-iterating.stderr +++ b/tests/ui/coroutine/yield-while-iterating.stderr @@ -9,8 +9,8 @@ LL | yield(); error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:58:20 | -LL | let mut b = || { - | -- mutable borrow occurs here +LL | let mut b = #[coroutine] || { + | -- mutable borrow occurs here LL | for p in &mut x { | - first borrow occurs due to use of `x` in coroutine ... diff --git a/tests/ui/coroutine/yield-while-local-borrowed.rs b/tests/ui/coroutine/yield-while-local-borrowed.rs index 7f8d1d4543d89..3db30c36712f0 100644 --- a/tests/ui/coroutine/yield-while-local-borrowed.rs +++ b/tests/ui/coroutine/yield-while-local-borrowed.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::cell::Cell; use std::ops::{Coroutine, CoroutineState}; @@ -9,7 +9,7 @@ fn borrow_local_inline() { // // (This error occurs because the region shows up in the type of // `b` and gets extended by region inference.) - let mut b = move || { + let mut b = #[coroutine] move || { let a = &mut 3; //~^ ERROR borrow may still be in use when coroutine yields yield (); @@ -20,7 +20,7 @@ fn borrow_local_inline() { fn borrow_local_inline_done() { // No error here -- `a` is not in scope at the point of `yield`. - let mut b = move || { + let mut b = #[coroutine] move || { { let a = &mut 3; } @@ -34,7 +34,7 @@ fn borrow_local() { // // (This error occurs because the region shows up in the type of // `b` and gets extended by region inference.) - let mut b = move || { + let mut b = #[coroutine] move || { let a = 3; { let b = &a; diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.rs b/tests/ui/coroutine/yield-while-ref-reborrowed.rs index 07c591758586b..2600d0b4124b1 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.rs +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.rs @@ -1,15 +1,16 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::ops::{CoroutineState, Coroutine}; use std::cell::Cell; +use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn reborrow_shared_ref(x: &i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the coroutine. - let mut b = move || { + let mut b = #[coroutine] + move || { let a = &*x; - yield(); + yield (); println!("{}", a); }; Pin::new(&mut b).resume(()); @@ -18,9 +19,10 @@ fn reborrow_shared_ref(x: &i32) { fn reborrow_mutable_ref(x: &mut i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the coroutine. - let mut b = move || { + let mut b = #[coroutine] + move || { let a = &mut *x; - yield(); + yield (); println!("{}", a); }; Pin::new(&mut b).resume(()); @@ -28,13 +30,14 @@ fn reborrow_mutable_ref(x: &mut i32) { fn reborrow_mutable_ref_2(x: &mut i32) { // ...but not OK to go on using `x`. - let mut b = || { + let mut b = #[coroutine] + || { let a = &mut *x; - yield(); + yield (); println!("{}", a); }; println!("{}", x); //~ ERROR Pin::new(&mut b).resume(()); } -fn main() { } +fn main() {} diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr index 62ac02653112e..7c9b766457dbf 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr @@ -1,8 +1,8 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access - --> $DIR/yield-while-ref-reborrowed.rs:36:20 + --> $DIR/yield-while-ref-reborrowed.rs:39:20 | -LL | let mut b = || { - | -- coroutine construction occurs here +LL | || { + | -- coroutine construction occurs here LL | let a = &mut *x; | -- first borrow occurs due to use of `x` in coroutine ... diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/debuginfo/backtrace-dylib-dep.rs index e2414073edef4..fcd1f92e28ebc 100644 --- a/tests/ui/debuginfo/backtrace-dylib-dep.rs +++ b/tests/ui/debuginfo/backtrace-dylib-dep.rs @@ -27,6 +27,7 @@ macro_rules! pos { }; } +#[collapse_debuginfo(yes)] macro_rules! check { ($($pos:expr),*) => ({ verify(&[$($pos,)* pos!()]); diff --git a/tests/ui/delegation/auxiliary/fn-header-aux.rs b/tests/ui/delegation/auxiliary/fn-header-aux.rs new file mode 100644 index 0000000000000..d26209a4f789f --- /dev/null +++ b/tests/ui/delegation/auxiliary/fn-header-aux.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(c_variadic)] + +pub unsafe fn unsafe_fn_extern() {} +pub extern "C" fn extern_fn_extern() {} +pub unsafe extern "C" fn variadic_fn_extern(n: usize, mut args: ...) {} +pub const fn const_fn_extern() {} +pub async fn async_fn_extern() {} diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs new file mode 100644 index 0000000000000..db20e1058e061 --- /dev/null +++ b/tests/ui/delegation/fn-header.rs @@ -0,0 +1,57 @@ +//@ check-pass +//@ edition:2018 +//@ aux-crate:fn_header_aux=fn-header-aux.rs + +#![feature(c_variadic)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![deny(unused_unsafe)] + +mod to_reuse { + pub unsafe fn unsafe_fn() {} + pub extern "C" fn extern_fn() {} + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} + pub const fn const_fn() {} + pub async fn async_fn() {} +} + +reuse to_reuse::unsafe_fn; +reuse to_reuse::extern_fn; +reuse to_reuse::variadic_fn; +reuse to_reuse::const_fn; +reuse to_reuse::async_fn; + +reuse fn_header_aux::unsafe_fn_extern; +reuse fn_header_aux::extern_fn_extern; +reuse fn_header_aux::variadic_fn_extern; +reuse fn_header_aux::const_fn_extern; +reuse fn_header_aux::async_fn_extern; + +const fn const_check() { + const_fn(); + const_fn_extern(); +} + +async fn async_check() { + async_fn().await; + async_fn_extern().await; +} + +fn main() { + unsafe { + unsafe_fn(); + unsafe_fn_extern(); + } + extern_fn(); + extern_fn_extern(); + let _: extern "C" fn() = extern_fn; + let _: extern "C" fn() = extern_fn_extern; + unsafe { + variadic_fn(0); + variadic_fn(0, 1); + variadic_fn_extern(0); + variadic_fn_extern(0, 1); + } + let _: unsafe extern "C" fn(usize, ...) = variadic_fn; + let _: unsafe extern "C" fn(usize, ...) = variadic_fn_extern; +} diff --git a/tests/ui/delegation/impl-trait.rs b/tests/ui/delegation/impl-trait.rs new file mode 100644 index 0000000000000..13df0155485c9 --- /dev/null +++ b/tests/ui/delegation/impl-trait.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo() -> impl Clone { 0 } +} + +reuse to_reuse::foo; + +trait Trait { + fn bar() -> impl Clone { 1 } +} + +struct S; +impl Trait for S {} + +impl S { + reuse to_reuse::foo; + reuse ::bar; +} + +fn main() { + foo().clone(); + ::bar().clone(); +} diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 9dccb12b57adb..5f78de97638b5 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -14,9 +14,9 @@ mod generics { fn foo3<'a: 'a>(_: &'a u32) {} reuse GenericTrait::bar; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet reuse GenericTrait::bar1; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet } struct F; @@ -73,26 +73,18 @@ mod opaque { } reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet - reuse to_reuse::opaque_ret; - //~^ ERROR delegation to a function with opaque type is not supported yet -} -mod fn_header { - mod to_reuse { - pub unsafe fn unsafe_fn() {} - pub extern "C" fn extern_fn() {} - pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - pub const fn const_fn() {} + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } } - reuse to_reuse::unsafe_fn; - //~^ ERROR delegation to unsafe functions is not supported yet - reuse to_reuse::extern_fn; - //~^ ERROR delegation to non Rust ABI functions is not supported yet - reuse to_reuse::variadic_fn; - //~^ ERROR delegation to variadic functions is not supported yet - reuse to_reuse::const_fn; - //~^ ERROR delegation to const functions is not supported yet + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } } mod recursive { diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index f6c49366899c1..e2cb04f977b1e 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -115,53 +115,46 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } LL | reuse to_reuse::opaque_arg; | ^^^^^^^^^^ -error: delegation to a function with opaque type is not supported yet - --> $DIR/not-supported.rs:76:21 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:83:25 | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | --------------------------------- callee defined here -... -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - -error: delegation to unsafe functions is not supported yet - --> $DIR/not-supported.rs:88:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ | -LL | pub unsafe fn unsafe_fn() {} - | ------------------------- callee defined here -... -LL | reuse to_reuse::unsafe_fn; - | ^^^^^^^^^ - -error: delegation to non Rust ABI functions is not supported yet - --> $DIR/not-supported.rs:90:21 +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:83:25 | -LL | pub extern "C" fn extern_fn() {} - | ----------------------------- callee defined here -... -LL | reuse to_reuse::extern_fn; - | ^^^^^^^^^ - -error: delegation to variadic functions is not supported yet - --> $DIR/not-supported.rs:92:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:82:5 | -LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - | ------------------------------------------------------------- callee defined here -... -LL | reuse to_reuse::variadic_fn; - | ^^^^^^^^^^^ +LL | impl ToReuse for u8 { + | ^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: delegation to const functions is not supported yet - --> $DIR/not-supported.rs:94:21 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:86:24 | -LL | pub const fn const_fn() {} - | ----------------------- callee defined here -... -LL | reuse to_reuse::const_fn; - | ^^^^^^^^ +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:86:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:85:5 + | +LL | impl ToReuse for u16 { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:107:22 + --> $DIR/not-supported.rs:99:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -169,7 +162,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 19 previous errors +error: aborting due to 16 previous errors -Some errors have detailed explanations: E0049, E0195. +Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs new file mode 100644 index 0000000000000..f4b3da76c56c7 --- /dev/null +++ b/tests/ui/delegation/rename.rs @@ -0,0 +1,20 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn a() {} +} + +reuse to_reuse::a as b; + +struct S; +impl S { + reuse to_reuse::a as b; +} + +fn main() { + b(); + S::b(); +} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 26ac532263fd0..a8523d25cab9b 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -40,7 +40,10 @@ note: if `Y` implemented `Clone`, you could clone the value --> $DIR/deriving-with-repr-packed.rs:16:1 | LL | struct Y(usize); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | struct X(Y); + | - you could clone this value = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index 9e17189671827..4d637c9728385 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -2,15 +2,13 @@ error[E0599]: the method `insert` exists for struct `HashSet`, but its tr --> $DIR/issue-91550.rs:8:8 | LL | struct Value(u32); - | ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq` + | ------------ doesn't satisfy `Value: Eq` or `Value: Hash` ... LL | hs.insert(Value(0)); | ^^^^^^ | = note: the following trait bounds were not satisfied: `Value: Eq` - `Value: PartialEq` - which is required by `Value: Eq` `Value: Hash` help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` | @@ -22,7 +20,7 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq` + | -------------------- doesn't satisfy `NoDerives: Eq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -37,9 +35,6 @@ LL | impl Object { | ^^ --------- | | | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialEq` - which is required by `NoDerives: Eq` help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` | LL + #[derive(Eq, PartialEq)] @@ -50,7 +45,7 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Ord` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -65,13 +60,6 @@ LL | impl Object { | ^^^ --------- | | | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialOrd` - which is required by `NoDerives: Ord` - `NoDerives: PartialEq` - which is required by `NoDerives: Ord` - `NoDerives: Eq` - which is required by `NoDerives: Ord` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] @@ -82,7 +70,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object $DIR/issue-91550.rs:28:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Ord` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord_and_partial_ord` not found for this struct @@ -100,13 +88,6 @@ LL | impl Object { | | | | | unsatisfied trait bound introduced here | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialEq` - which is required by `NoDerives: Ord` - `NoDerives: Eq` - which is required by `NoDerives: Ord` - `NoDerives: PartialEq` - which is required by `NoDerives: PartialOrd` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.rs b/tests/ui/diagnostic-flags/colored-session-opt-error.rs index 932c2bf247379..e850345fbf16b 100644 --- a/tests/ui/diagnostic-flags/colored-session-opt-error.rs +++ b/tests/ui/diagnostic-flags/colored-session-opt-error.rs @@ -1,6 +1,4 @@ //@ check-pass //@ ignore-windows //@ compile-flags: -Cremark=foo --error-format=human --color=always -// Temporary until next release: -//@ ignore-stage2 fn main() {} diff --git a/tests/ui/drop/dynamic-drop.rs b/tests/ui/drop/dynamic-drop.rs index f848a1a340b29..b695b5702d943 100644 --- a/tests/ui/drop/dynamic-drop.rs +++ b/tests/ui/drop/dynamic-drop.rs @@ -1,7 +1,7 @@ //@ run-pass //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![feature(if_let_guard)] #![allow(unused_assignments)] @@ -176,7 +176,7 @@ fn vec_simple(a: &Allocator) { fn coroutine(a: &Allocator, run_count: usize) { assert!(run_count < 4); - let mut gen = || { + let mut gen = #[coroutine] || { (a.alloc(), yield a.alloc(), a.alloc(), diff --git a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr index 89aded9134f9f..0d53fb024acab 100644 --- a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr +++ b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:17:20 diff --git a/tests/ui/error-codes/E0229.stderr b/tests/ui/error-codes/E0229.stderr index bd8e1955ac684..ae7dc9ac26599 100644 --- a/tests/ui/error-codes/E0229.stderr +++ b/tests/ui/error-codes/E0229.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | fn baz(x: &>::A) {} | ^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | fn baz(x: &>::A) {} + | ~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/E0229.rs:13:25 @@ -11,6 +16,10 @@ LL | fn baz(x: &>::A) {} | ^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | fn baz(x: &>::A) {} + | ~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/E0229.rs:13:25 @@ -19,6 +28,10 @@ LL | fn baz(x: &>::A) {} | ^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | fn baz(x: &>::A) {} + | ~~~~~~~ error[E0277]: the trait bound `I: Foo` is not satisfied --> $DIR/E0229.rs:13:15 diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr index 900cb706bd97c..343bca9a72e24 100644 --- a/tests/ui/error-codes/E0504.stderr +++ b/tests/ui/error-codes/E0504.stderr @@ -18,7 +18,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value --> $DIR/E0504.rs:1:1 | LL | struct FancyNum { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let fancy_ref = &fancy_num; + | ---------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr index ce01298a70d90..266df9ea32a71 100644 --- a/tests/ui/error-codes/E0505.stderr +++ b/tests/ui/error-codes/E0505.stderr @@ -15,7 +15,10 @@ note: if `Value` implemented `Clone`, you could clone the value --> $DIR/E0505.rs:1:1 | LL | struct Value {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _ref_to_val: &Value = &x; + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr index 60a4daa9d382e..70d99ea2cce5c 100644 --- a/tests/ui/error-codes/E0507.stderr +++ b/tests/ui/error-codes/E0507.stderr @@ -15,7 +15,10 @@ note: if `TheDarkKnight` implemented `Clone`, you could clone the value --> $DIR/E0507.rs:3:1 | LL | struct TheDarkKnight; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | x.borrow().nothing_is_true(); + | ---------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr index 96d3bcb67a57f..fcfac399e0df5 100644 --- a/tests/ui/error-codes/E0508-fail.stderr +++ b/tests/ui/error-codes/E0508-fail.stderr @@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/E0508-fail.rs:1:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _value = array[0]; + | -------- you could clone this value help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr index c1b622e243213..b9fa0f4d17a5f 100644 --- a/tests/ui/error-codes/E0508.stderr +++ b/tests/ui/error-codes/E0508.stderr @@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/E0508.rs:1:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _value = array[0]; + | -------- you could clone this value help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr index 75c372d044019..628a253e08593 100644 --- a/tests/ui/error-codes/E0509.stderr +++ b/tests/ui/error-codes/E0509.stderr @@ -11,7 +11,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value --> $DIR/E0509.rs:1:1 | LL | struct FancyNum { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let fancy_field = drop_struct.fancy; + | ----------------- you could clone this value help: consider borrowing here | LL | let fancy_field = &drop_struct.fancy; diff --git a/tests/ui/error-codes/E0522.rs b/tests/ui/error-codes/E0522.rs index 1414e82408cef..ec9e6d257743e 100644 --- a/tests/ui/error-codes/E0522.rs +++ b/tests/ui/error-codes/E0522.rs @@ -2,7 +2,7 @@ #[lang = "cookie"] fn cookie() -> ! { -//~^^ ERROR definition of an unknown language item: `cookie` [E0522] +//~^^ ERROR definition of an unknown lang item: `cookie` [E0522] loop {} } diff --git a/tests/ui/error-codes/E0522.stderr b/tests/ui/error-codes/E0522.stderr index 66359cbacc846..82bbf07959405 100644 --- a/tests/ui/error-codes/E0522.stderr +++ b/tests/ui/error-codes/E0522.stderr @@ -1,8 +1,8 @@ -error[E0522]: definition of an unknown language item: `cookie` +error[E0522]: definition of an unknown lang item: `cookie` --> $DIR/E0522.rs:3:1 | LL | #[lang = "cookie"] - | ^^^^^^^^^^^^^^^^^^ definition of unknown language item `cookie` + | ^^^^^^^^^^^^^^^^^^ definition of unknown lang item `cookie` error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0718.rs b/tests/ui/error-codes/E0718.rs index 909cae0ba25a2..358bc348ec76d 100644 --- a/tests/ui/error-codes/E0718.rs +++ b/tests/ui/error-codes/E0718.rs @@ -1,7 +1,7 @@ #![feature(lang_items)] // Box is expected to be a struct, so this will error. -#[lang = "owned_box"] //~ ERROR language item must be applied to a struct +#[lang = "owned_box"] //~ ERROR lang item must be applied to a struct static X: u32 = 42; fn main() {} diff --git a/tests/ui/error-codes/E0718.stderr b/tests/ui/error-codes/E0718.stderr index 9a3db136d23c0..ec7462765f81f 100644 --- a/tests/ui/error-codes/E0718.stderr +++ b/tests/ui/error-codes/E0718.stderr @@ -1,4 +1,4 @@ -error[E0718]: `owned_box` language item must be applied to a struct +error[E0718]: `owned_box` lang item must be applied to a struct --> $DIR/E0718.rs:4:1 | LL | #[lang = "owned_box"] diff --git a/tests/ui/error-emitter/highlighting.rs b/tests/ui/error-emitter/highlighting.rs index 16794a8091430..b3c1acbd342ca 100644 --- a/tests/ui/error-emitter/highlighting.rs +++ b/tests/ui/error-emitter/highlighting.rs @@ -3,8 +3,6 @@ //@ compile-flags: --error-format=human --color=always //@ error-pattern:for<'a>  //@ edition:2018 -// Temporary until next release: -//@ ignore-stage2 use core::pin::Pin; use core::future::Future; diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index b5791858ab60e..be92c00c19bdc 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -23,17 +23,17 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:24:11 + --> $DIR/highlighting.rs:22:11 | LL | query(wrapped_fn); - | ----- ^^^^^^^^^^ one type is more general than the other + | ----- ^^^^^^^^^^ one type is more general than the other - | | + | | - | arguments to this function are incorrect + | arguments to this function are incorrect | @@ -43,19 +43,19 @@ note: function defined here - --> $DIR/highlighting.rs:13:4 + --> $DIR/highlighting.rs:11:4 | LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static LL | | )>>) {} - | |___- + | |___- diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index 6b714d64ade27..152245da9ddc1 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -24,17 +24,17 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:24:11 + --> $DIR/highlighting.rs:22:11 | LL | query(wrapped_fn); - | ----- ^^^^^^^^^^ one type is more general than the other + | ----- ^^^^^^^^^^ one type is more general than the other - | | + | | - | arguments to this function are incorrect + | arguments to this function are incorrect | @@ -44,19 +44,19 @@ note: function defined here - --> $DIR/highlighting.rs:13:4 + --> $DIR/highlighting.rs:11:4 | LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static LL | | )>>) {} - | |___- + | |___- diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.rs b/tests/ui/error-emitter/multiline-multipart-suggestion.rs index 12c9324edb718..a938b280ca2ec 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.rs +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.rs @@ -1,7 +1,5 @@ //@ compile-flags: --error-format=human --color=always //@ error-pattern: missing lifetime specifier -// Temporary until next release: -//@ ignore-stage2 fn short(foo_bar: &Vec<&i32>) -> &i32 { &12 diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.svg index 3aa607ea693da..c0fb98555ad86 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.svg @@ -23,13 +23,13 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:6:34 + --> $DIR/multiline-multipart-suggestion.rs:4:34 | LL | fn short(foo_bar: &Vec<&i32>) -> &i32 { - | ---------- ^ expected named lifetime parameter + | ---------- ^ expected named lifetime parameter | @@ -47,19 +47,19 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:13:6 + --> $DIR/multiline-multipart-suggestion.rs:11:6 | LL | foo_bar: &Vec<&i32>, - | ---------- + | ---------- LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, LL | ) -> &i32 { - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | @@ -73,7 +73,7 @@ LL ~ foo_bar: &'a Vec<&'a i32>, - LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, + LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, LL ~ ) -> &'a i32 { @@ -83,13 +83,13 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:18:29 + --> $DIR/multiline-multipart-suggestion.rs:16:29 | LL | foo_bar: &Vec<&i32>) -> &i32 { - | ---------- ^ expected named lifetime parameter + | ---------- ^ expected named lifetime parameter | diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg index 330eb96e4aea2..61b544001f08c 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg @@ -23,13 +23,13 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:6:34 + --> $DIR/multiline-multipart-suggestion.rs:4:34 | LL | fn short(foo_bar: &Vec<&i32>) -> &i32 { - | ---------- ^ expected named lifetime parameter + | ---------- ^ expected named lifetime parameter | @@ -47,19 +47,19 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:13:6 + --> $DIR/multiline-multipart-suggestion.rs:11:6 | LL | foo_bar: &Vec<&i32>, - | ---------- + | ---------- LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, LL | ) -> &i32 { - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | @@ -73,7 +73,7 @@ LL ~ foo_bar: &'a Vec<&'a i32>, - LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, + LL | something_very_long_so_that_the_line_will_wrap_around__________: i32, LL ~ ) -> &'a i32 { @@ -83,13 +83,13 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:18:29 + --> $DIR/multiline-multipart-suggestion.rs:16:29 | LL | foo_bar: &Vec<&i32>) -> &i32 { - | ---------- ^ expected named lifetime parameter + | ---------- ^ expected named lifetime parameter | diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs index 93bf83ecf53c8..d90fb765a237a 100644 --- a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs +++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs @@ -4,6 +4,6 @@ fn main() { let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures - let _coroutine = #[track_caller] || { yield; }; //~ `#[track_caller]` on closures + let _coroutine = #[coroutine] #[track_caller] || { yield; }; //~ `#[track_caller]` on closures let _future = #[track_caller] async {}; //~ `#[track_caller]` on closures } diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr index 17b5e6016a461..0b12b73fd1fff 100644 --- a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr +++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr @@ -9,10 +9,10 @@ LL | let _closure = #[track_caller] || {}; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/feature-gate-closure_track_caller.rs:7:22 + --> $DIR/feature-gate-closure_track_caller.rs:7:35 | -LL | let _coroutine = #[track_caller] || { yield; }; - | ^^^^^^^^^^^^^^^ +LL | let _coroutine = #[coroutine] #[track_caller] || { yield; }; + | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs b/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs deleted file mode 100644 index f73bf579f6d13..0000000000000 --- a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[collapse_debuginfo] -//~^ ERROR the `#[collapse_debuginfo]` attribute is an experimental feature -macro_rules! foo { - ($e:expr) => { $e } -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr b/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr deleted file mode 100644 index f361a76b4a739..0000000000000 --- a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the `#[collapse_debuginfo]` attribute is an experimental feature - --> $DIR/feature-gate-collapse_debuginfo.rs:1:1 - | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100758 for more information - = help: add `#![feature(collapse_debuginfo)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr index 1cef163cef5c2..3bb48e4a37a4a 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr @@ -8,8 +8,19 @@ LL | yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -18,13 +29,24 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/feature-gate-coroutines.rs:5:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr index 403f0549aef27..65e7737ef84d5 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr @@ -9,7 +9,7 @@ LL | yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:16:5 + --> $DIR/feature-gate-coroutines.rs:18:5 | LL | yield; | ^^^^^ @@ -29,7 +29,7 @@ LL | yield; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:17:5 + --> $DIR/feature-gate-coroutines.rs:19:5 | LL | yield 0; | ^^^^^^^ @@ -49,8 +49,19 @@ LL | yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -60,13 +71,24 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/feature-gate-coroutines.rs:5:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index b3df2351b680b..28dce8596d396 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -5,9 +5,11 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield expression outside of coroutine literal //[none]~^^ ERROR yield syntax is experimental + //~^^^ ERROR `yield` can only be used let _ = || yield true; //~ ERROR yield syntax is experimental //[none]~^ ERROR yield syntax is experimental + //~^^ ERROR `yield` can only be used } #[cfg(FALSE)] diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs index 83366ea02b09a..eea6a21ce274c 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs @@ -3,7 +3,7 @@ use std::cell::Cell; trait Trait{ - fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self> + fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: `Cell<&Self>` } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr index e727b69ffceb8..2150effc3b74d 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr @@ -1,4 +1,4 @@ -error[E0307]: invalid `self` parameter type: Cell<&Self> +error[E0307]: invalid `self` parameter type: `Cell<&Self>` --> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19 | LL | fn cell(self: Cell<&Self>); diff --git a/tests/ui/feature-gates/feature-gate-inline_const.rs b/tests/ui/feature-gates/feature-gate-inline_const.rs deleted file mode 100644 index 43ff90d234cb7..0000000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let _ = const { - //~^ ERROR inline-const is experimental [E0658] - true - }; -} diff --git a/tests/ui/feature-gates/feature-gate-inline_const.stderr b/tests/ui/feature-gates/feature-gate-inline_const.stderr deleted file mode 100644 index 6cf675065f34d..0000000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: inline-const is experimental - --> $DIR/feature-gate-inline_const.rs:2:13 - | -LL | let _ = const { - | ^^^^^ - | - = note: see issue #76001 for more information - = help: add `#![feature(inline_const)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-lang-items.rs b/tests/ui/feature-gates/feature-gate-lang-items.rs index 93262f2171bfe..d6fd5472a0c1d 100644 --- a/tests/ui/feature-gates/feature-gate-lang-items.rs +++ b/tests/ui/feature-gates/feature-gate-lang-items.rs @@ -1,5 +1,5 @@ -#[lang = "foo"] //~ ERROR language items are subject to change - //~^ ERROR definition of an unknown language item: `foo` +#[lang = "foo"] //~ ERROR lang items are subject to change + //~^ ERROR definition of an unknown lang item: `foo` trait Foo {} fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-lang-items.stderr b/tests/ui/feature-gates/feature-gate-lang-items.stderr index 54787e03784e4..c5caffbdc94dd 100644 --- a/tests/ui/feature-gates/feature-gate-lang-items.stderr +++ b/tests/ui/feature-gates/feature-gate-lang-items.stderr @@ -1,4 +1,4 @@ -error[E0658]: language items are subject to change +error[E0658]: lang items are subject to change --> $DIR/feature-gate-lang-items.rs:1:1 | LL | #[lang = "foo"] @@ -7,11 +7,11 @@ LL | #[lang = "foo"] = help: add `#![feature(lang_items)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0522]: definition of an unknown language item: `foo` +error[E0522]: definition of an unknown lang item: `foo` --> $DIR/feature-gate-lang-items.rs:1:1 | LL | #[lang = "foo"] - | ^^^^^^^^^^^^^^^ definition of unknown language item `foo` + | ^^^^^^^^^^^^^^^ definition of unknown lang item `foo` error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr index 815013733a98b..9bab366f7fef1 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[optimize]` attribute is an experimental feature - --> $DIR/feature-gate-optimize_attribute.rs:7:1 + --> $DIR/feature-gate-optimize_attribute.rs:4:1 | LL | #[optimize(size)] | ^^^^^^^^^^^^^^^^^ @@ -9,30 +9,30 @@ LL | #[optimize(size)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[optimize]` attribute is an experimental feature - --> $DIR/feature-gate-optimize_attribute.rs:10:1 + --> $DIR/feature-gate-optimize_attribute.rs:7:1 | -LL | #[optimize(speed)] - | ^^^^^^^^^^^^^^^^^^ +LL | #[optimize(size)] + | ^^^^^^^^^^^^^^^^^ | = note: see issue #54882 for more information = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[optimize]` attribute is an experimental feature - --> $DIR/feature-gate-optimize_attribute.rs:13:1 + --> $DIR/feature-gate-optimize_attribute.rs:10:1 | -LL | #[optimize(banana)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[optimize(speed)] + | ^^^^^^^^^^^^^^^^^^ | = note: see issue #54882 for more information = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[optimize]` attribute is an experimental feature - --> $DIR/feature-gate-optimize_attribute.rs:4:1 + --> $DIR/feature-gate-optimize_attribute.rs:13:1 | -LL | #[optimize(size)] - | ^^^^^^^^^^^^^^^^^ +LL | #[optimize(banana)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #54882 for more information = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr b/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr index 677fef3a926b5..e4cc088e2cd3d 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr @@ -1,3 +1,9 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-43106-gating-of-stable.rs:10:1 + | +LL | #[stable()] + | ^^^^^^^^^^^ + error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:14:9 | @@ -28,12 +34,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra LL | #[stable()] | ^^^^^^^^^^^ -error[E0734]: stability attributes may not be used outside of the standard library - --> $DIR/issue-43106-gating-of-stable.rs:10:1 - | -LL | #[stable()] - | ^^^^^^^^^^^ - error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:7:1 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr b/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr index a2f361878c6db..f7c6e631cd177 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr @@ -1,3 +1,9 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-43106-gating-of-unstable.rs:10:1 + | +LL | #[unstable()] + | ^^^^^^^^^^^^^ + error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:14:9 | @@ -28,12 +34,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra LL | #[unstable()] | ^^^^^^^^^^^^^ -error[E0734]: stability attributes may not be used outside of the standard library - --> $DIR/issue-43106-gating-of-unstable.rs:10:1 - | -LL | #[unstable()] - | ^^^^^^^^^^^^^ - error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:7:1 | diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs new file mode 100644 index 0000000000000..313be6f28cdcc --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.rs @@ -0,0 +1,58 @@ +//! Test that coercing between function items of the same function, +//! but with different generic args succeeds in typeck, but then fails +//! in borrowck when the lifetimes can't actually be merged. + +fn foo(t: T) -> T { + t +} + +fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'a ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'b ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'c ()>; + x(a); + x(b); + x(c); +} + +fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'c ()>; + let _: &'c () = x(a); //~ ERROR lifetime may not live long enough +} + +fn h<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'a ()>; + let _: &'a () = x(c); +} + +fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'c ()>; + x = foo::<&'b ()>; //~ ERROR lifetime may not live long enough + x = foo::<&'a ()>; //~ ERROR lifetime may not live long enough + x(a); + x(b); + x(c); +} + +fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'b ()>, //~ ERROR lifetime may not live long enough + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + x(a); + x(b); + x(c); +} + +fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'c ()>, + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + + x(a); + x(b); //~ ERROR lifetime may not live long enough + x(c); +} + +fn main() {} diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr new file mode 100644 index 0000000000000..ec4a1bde7fd61 --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -0,0 +1,154 @@ +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:10:17 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:11:5 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:20:12 + | +LL | fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +LL | let x = foo::<&'c ()>; +LL | let _: &'c () = x(a); + | ^^^^^^ type annotation requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:30:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'c ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:31:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x = foo::<&'a ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:39:17 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let x = match true { +LL | true => foo::<&'b ()>, + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:40:18 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:50:18 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:54:5 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x(b); + | ^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'c` + = help: add bound `'b: 'a` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/fn/fn_def_opaque_coercion.rs b/tests/ui/fn/fn_def_opaque_coercion.rs new file mode 100644 index 0000000000000..0a8810cf4f8ac --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion.rs @@ -0,0 +1,69 @@ +//! Test that coercing between function items of the same function, +//! but with different generic args works. + +//@check-pass + +#![feature(type_alias_impl_trait)] + +fn foo(t: T) -> T { + t +} + +type F = impl Sized; + +fn f(a: F) { + let mut x = foo::; + x = foo::<()>; + x(a); + x(()); +} + +type G = impl Sized; + +fn g(a: G) { + let x = foo::<()>; + let _: () = x(a); +} + +type H = impl Sized; + +fn h(a: H) { + let x = foo::; + let _: H = x(()); +} + +type I = impl Sized; + +fn i(a: I) { + let mut x = foo::<()>; + x = foo::; + x(a); + x(()); +} + +type J = impl Sized; + +fn j(a: J) { + let x = match true { + true => foo::, + false => foo::<()>, + }; + x(a); + x(()); +} + +fn k() -> impl Sized { + fn bind T>(_: T, f: F) -> F { + f + } + let x = match true { + true => { + let f = foo; + bind(k(), f) + } + false => foo::<()>, + }; + todo!() +} + +fn main() {} diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs index 81f2027286791..30e25ca8edccd 100644 --- a/tests/ui/fn/suggest-return-closure.rs +++ b/tests/ui/fn/suggest-return-closure.rs @@ -18,6 +18,7 @@ fn fn_mut() -> _ { //~| NOTE for more information on `Fn` traits and closure types let x = String::new(); //~^ HELP: consider changing this to be mutable + //~| NOTE binding `x` declared here |c| { //~ NOTE: value captured here x.push(c); //~^ ERROR: does not live long enough diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index 8e80a11fe1b08..d276ce8be2ba5 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/suggest-return-closure.rs:31:13 + --> $DIR/suggest-return-closure.rs:32:13 | LL | fn fun() -> _ { | ^ @@ -32,7 +32,7 @@ LL | fn fun() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/suggest-return-closure.rs:22:9 + --> $DIR/suggest-return-closure.rs:23:9 | LL | let x = String::new(); | - help: consider changing this to be mutable: `mut x` @@ -41,8 +41,11 @@ LL | x.push(c); | ^ cannot borrow as mutable error[E0597]: `x` does not live long enough - --> $DIR/suggest-return-closure.rs:22:9 + --> $DIR/suggest-return-closure.rs:23:9 | +LL | let x = String::new(); + | - binding `x` declared here +... LL | |c| { | --- value captured here LL | x.push(c); diff --git a/tests/ui/generic-associated-types/issue-102335-gat.stderr b/tests/ui/generic-associated-types/issue-102335-gat.stderr index f5e782e92fc6a..23b114a3a55e2 100644 --- a/tests/ui/generic-associated-types/issue-102335-gat.stderr +++ b/tests/ui/generic-associated-types/issue-102335-gat.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | type A: S = ()>; | ^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type A: S = ()>; + | ~~~~~~~~~~ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-102335-gat.rs:2:21 @@ -11,6 +16,10 @@ LL | type A: S = ()>; | ^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type A: S = ()>; + | ~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs index 86da6ebfaaa42..d7dff329df1e6 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs @@ -29,5 +29,5 @@ where fn main() { let mut list = RcNode::::new(); - //~^ ERROR trait bounds were not satisfied + //~^ ERROR the variant or associated item `new` exists for enum `Node`, but its trait bounds were not satisfied } diff --git a/tests/ui/impl-trait/future-no-bound-vars-ice-112347.rs b/tests/ui/impl-trait/future-no-bound-vars-ice-112347.rs new file mode 100644 index 0000000000000..dc4dc9e220d51 --- /dev/null +++ b/tests/ui/impl-trait/future-no-bound-vars-ice-112347.rs @@ -0,0 +1,29 @@ +// issue: rust-lang/rust#112347 +// ICE future has no bound vars +//@ edition:2021 +//@ check-pass + +#![feature(type_alias_impl_trait)] + +use std::future::Future; + +type Fut<'a> = impl Future + 'a; + +fn foo<'a>(_: &()) -> Fut<'_> { + async {} +} + +trait Test { + fn hello(); +} + +impl Test for () +where + for<'a> Fut<'a>: Future, +{ + fn hello() {} +} + +fn main() { + <()>::hello(); +} diff --git a/tests/ui/impl-trait/issues/issue-58504.rs b/tests/ui/impl-trait/issues/issue-58504.rs index 4f7a35e81b80b..856e1297e58b8 100644 --- a/tests/ui/impl-trait/issues/issue-58504.rs +++ b/tests/ui/impl-trait/issues/issue-58504.rs @@ -3,7 +3,7 @@ use std::ops::Coroutine; fn mk_gen() -> impl Coroutine { - || { loop { yield; } } + #[coroutine] || { loop { yield; } } } fn main() { diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs index 11a75737e5545..56c63a1daa867 100644 --- a/tests/ui/impl-trait/issues/issue-62742.rs +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -1,12 +1,17 @@ use std::marker::PhantomData; -fn _alias_check() { +fn a() { WrongImpl::foo(0i32); - //~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied - //~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied + //~^ ERROR overflow assigning `_` to `[_]` +} + +fn b() { WrongImpl::<()>::foo(0i32); //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied //~| ERROR trait bounds were not satisfied +} + +fn c() { CorrectImpl::foo(0i32); } diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index 9ec581c231b7b..7a1bcfc70d54f 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -1,33 +1,11 @@ -error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied - --> $DIR/issue-62742.rs:4:5 +error[E0275]: overflow assigning `_` to `[_]` + --> $DIR/issue-62742.rs:4:16 | LL | WrongImpl::foo(0i32); - | ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` - | - = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` -note: required by a bound in `SafeImpl::::foo` - --> $DIR/issue-62742.rs:29:20 - | -LL | impl> SafeImpl { - | ^^^^^^ required by this bound in `SafeImpl::::foo` -LL | pub fn foo(value: A::Value) {} - | --- required by a bound in this associated function - -error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied - --> $DIR/issue-62742.rs:4:5 - | -LL | WrongImpl::foo(0i32); - | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` - | - = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` -note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:27:35 - | -LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ^^^^^^ required by this bound in `SafeImpl` + | ^^^ error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied - --> $DIR/issue-62742.rs:7:22 + --> $DIR/issue-62742.rs:9:22 | LL | WrongImpl::<()>::foo(0i32); | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds @@ -39,20 +17,20 @@ LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ----------------------------------------- function or associated item `foo` not found for this struct | note: trait bound `RawImpl<()>: Raw<()>` was not satisfied - --> $DIR/issue-62742.rs:29:20 + --> $DIR/issue-62742.rs:34:20 | LL | impl> SafeImpl { | ^^^^^^ -------------- | | | unsatisfied trait bound introduced here note: the trait `Raw` must be implemented - --> $DIR/issue-62742.rs:13:1 + --> $DIR/issue-62742.rs:18:1 | LL | pub trait Raw { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied - --> $DIR/issue-62742.rs:7:5 + --> $DIR/issue-62742.rs:9:5 | LL | WrongImpl::<()>::foo(0i32); | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` @@ -60,12 +38,12 @@ LL | WrongImpl::<()>::foo(0i32); = help: the trait `Raw<[()]>` is implemented for `RawImpl<()>` = help: for that trait implementation, expected `[()]`, found `()` note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:27:35 + --> $DIR/issue-62742.rs:32:35 | LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0599. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277, E0599. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/issues/issue-84073.rs b/tests/ui/impl-trait/issues/issue-84073.rs index 85d9d461fd9ad..7acee44a722a4 100644 --- a/tests/ui/impl-trait/issues/issue-84073.rs +++ b/tests/ui/impl-trait/issues/issue-84073.rs @@ -29,5 +29,6 @@ where } fn main() { - Race::new(|race| race.when()); //~ ERROR overflow assigning `_` to `Option<_>` + Race::new(|race| race.when()); + //~^ ERROR overflow assigning `_` to `Option<_>` } diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr index ab119a8a4f456..0f4c6e83fbe70 100644 --- a/tests/ui/impl-trait/issues/issue-84073.stderr +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `_` to `Option<_>` - --> $DIR/issue-84073.rs:32:22 + --> $DIR/issue-84073.rs:32:27 | LL | Race::new(|race| race.when()); - | ^^^^ + | ^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/lifetimes.rs b/tests/ui/impl-trait/lifetimes.rs index 93a4801fa40ef..df64b685eab85 100644 --- a/tests/ui/impl-trait/lifetimes.rs +++ b/tests/ui/impl-trait/lifetimes.rs @@ -115,7 +115,7 @@ impl<'unnecessary_lifetime> MyVec { } fn coroutine_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized { - || yield + #[coroutine] || yield } } diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index ccd073b807094..422c2e439cf0b 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -3,7 +3,6 @@ #![feature(type_alias_impl_trait)] #![feature(const_trait_impl)] #![feature(const_refs_to_cell)] -#![feature(inline_const)] use std::marker::Destruct; diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 7ae8306d74d5d..fbd41b61730e6 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,11 +1,11 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:25:42 + --> $DIR/normalize-tait-in-const.rs:24:42 | LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^^^^^^^^^^ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:26:5 + --> $DIR/normalize-tait-in-const.rs:25:5 | LL | fun(filter_positive()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/normalize-tait-in-const.rs:25:79 + --> $DIR/normalize-tait-in-const.rs:24:79 | LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^ the destructor for this type cannot be evaluated in constant functions diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs new file mode 100644 index 0000000000000..39c8c0def6bff --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs @@ -0,0 +1,9 @@ +// We used to fatal error without any useful diagnostic when we had an unexpected +// token due to a strange interaction between the sequence parsing code and the +// param/lifetime parsing code. + +fn hello() -> impl use<'a {}> Sized {} +//~^ ERROR expected one of `,` or `>`, found `{` +//~| ERROR expected item, found `>` + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr new file mode 100644 index 0000000000000..989c479b2484e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr @@ -0,0 +1,16 @@ +error: expected one of `,` or `>`, found `{` + --> $DIR/unexpected-token.rs:5:27 + | +LL | fn hello() -> impl use<'a {}> Sized {} + | ^ expected one of `,` or `>` + +error: expected item, found `>` + --> $DIR/unexpected-token.rs:5:29 + | +LL | fn hello() -> impl use<'a {}> Sized {} + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr index c0b399746eaf9..96db2030a405c 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:14:23 + --> $DIR/recursive-coroutine-boxed.rs:15:23 | LL | let mut gen = Box::pin(foo()); | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` @@ -13,7 +13,7 @@ LL | let mut gen = Box::::pin(foo()); | +++++ error[E0308]: mismatched types - --> $DIR/recursive-coroutine-boxed.rs:13:5 + --> $DIR/recursive-coroutine-boxed.rs:14:18 | LL | fn foo() -> impl Coroutine { | --------------------------------------- @@ -21,7 +21,8 @@ LL | fn foo() -> impl Coroutine { | the expected opaque type | expected `impl Coroutine` because of return type ... -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let mut gen = Box::pin(foo()); LL | | LL | | let mut r = gen.as_mut().resume(()); @@ -31,7 +32,7 @@ LL | | } | |_____^ types differ | = note: expected opaque type `impl Coroutine` - found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:13:5: 13:7}` + found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:14:18: 14:20}` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 02c75be0f3aa0..24a77d7311419 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -10,7 +10,8 @@ fn foo() -> impl Coroutine { // FIXME(-Znext-solver): this fails with a mismatched types as the // hidden type of the opaque ends up as {type error}. We should not // emit errors for such goals. - || { //[next]~ ERROR mismatched types + + #[coroutine] || { //[next]~ ERROR mismatched types let mut gen = Box::pin(foo()); //[next]~^ ERROR type annotations needed let mut r = gen.as_mut().resume(()); diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr index ee87c483d0d03..9814187e179ef 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -1,8 +1,8 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:11:5 + --> $DIR/recursive-coroutine-indirect.rs:11:18 | -LL | move || { - | ^^^^^^^ +LL | #[coroutine] move || { + | ^^^^^^^ LL | let x = coroutine_hold(); | - recursive call here diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr index ee87c483d0d03..9814187e179ef 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr @@ -1,8 +1,8 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:11:5 + --> $DIR/recursive-coroutine-indirect.rs:11:18 | -LL | move || { - | ^^^^^^^ +LL | #[coroutine] move || { + | ^^^^^^^ LL | let x = coroutine_hold(); | - recursive call here diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs index bba9792fe3cfa..cec2176049b87 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.rs +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -8,7 +8,7 @@ #![feature(coroutines)] #![allow(unconditional_recursion)] fn coroutine_hold() -> impl Sized { - move || { //~ ERROR recursion in a coroutine requires boxing + #[coroutine] move || { //~ ERROR recursion in a coroutine requires boxing let x = coroutine_hold(); yield; x; diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 432f80a1763e5..8b9dac0e29b0b 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -57,6 +57,8 @@ fn coroutine_sig() -> impl Sized { fn coroutine_capture() -> impl Sized { //~^ ERROR let x = coroutine_capture(); + + #[coroutine] move || { yield; x; diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index d5b8c531fd6e0..2d2731e4368f5 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -98,10 +98,10 @@ LL | | yield; LL | | x; | | - coroutine captures itself here LL | | } - | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:60:5: 60:12}` + | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:62:5: 62:12}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:66:35 + --> $DIR/recursive-impl-trait-type-indirect.rs:68:35 | LL | fn substs_change() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -110,7 +110,7 @@ LL | (substs_change::<&T>(),) | ------------------------ returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:76:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:78:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ recursive opaque type @@ -122,7 +122,7 @@ LL | fn mutual_recursion_b() -> impl Sized { | ---------- returning this opaque type `impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:81:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:83:28 | LL | fn mutual_recursion() -> impl Sync { | --------- returning this opaque type `impl Sync` diff --git a/tests/ui/imports/issue-59764.stderr b/tests/ui/imports/issue-59764.stderr index fe58eb97b8dbf..293c2a60d8033 100644 --- a/tests/ui/imports/issue-59764.stderr +++ b/tests/ui/imports/issue-59764.stderr @@ -208,9 +208,9 @@ LL | makro as foobar} help: a macro with this name exists at the root of the crate | LL ~ issue_59764::{makro as foobar, -LL | +LL | ... -LL | +LL | LL ~ foo::{baz} | diff --git a/tests/ui/inference/issue-80409.compat.stderr b/tests/ui/inference/issue-80409.compat.stderr new file mode 100644 index 0000000000000..2f3f6cef20926 --- /dev/null +++ b/tests/ui/inference/issue-80409.compat.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `usize: Fsm` is not satisfied + --> $DIR/issue-80409.rs:36:31 + | +LL | builder.state().on_entry(|_| {}); + | ^ the trait `Fsm` is not implemented for `usize` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-80409.rs:26:1 + | +LL | trait Fsm { + | ^^^^^^^^^ +note: required by a bound in `StateContext` + --> $DIR/issue-80409.rs:30:31 + | +LL | struct StateContext<'a, TFsm: Fsm> { + | ^^^ required by this bound in `StateContext` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index c772225be7549..2f3f6cef20926 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -1,14 +1,20 @@ -error: internal compiler error: error performing operation: fully_perform - --> $DIR/issue-80409.rs:49:30 +error[E0277]: the trait bound `usize: Fsm` is not satisfied + --> $DIR/issue-80409.rs:36:31 | LL | builder.state().on_entry(|_| {}); - | ^^^ + | ^ the trait `Fsm` is not implemented for `usize` | -note: - --> $DIR/issue-80409.rs:49:30 +help: this trait has no implementations, consider adding one + --> $DIR/issue-80409.rs:26:1 | -LL | builder.state().on_entry(|_| {}); - | ^^^ +LL | trait Fsm { + | ^^^^^^^^^ +note: required by a bound in `StateContext` + --> $DIR/issue-80409.rs:30:31 + | +LL | struct StateContext<'a, TFsm: Fsm> { + | ^^^ required by this bound in `StateContext` + +error: aborting due to 1 previous error -query stack during panic: -end of query stack +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs index dfb84563e6d80..86dac3cda9199 100644 --- a/tests/ui/inference/issue-80409.rs +++ b/tests/ui/inference/issue-80409.rs @@ -1,18 +1,5 @@ -// This should not pass, because `usize: Fsm` does not hold. However, it currently ICEs. - -// ignore-tidy-linelength - //@ revisions: compat no-compat -//@[compat] check-pass //@[no-compat] compile-flags: -Zno-implied-bounds-compat -//@[no-compat] check-fail -//@[no-compat] known-bug: #80409 -//@[no-compat] failure-status: 101 -//@[no-compat] normalize-stderr-test "delayed at.*" -> "" -//@[no-compat] normalize-stderr-test "note: .*\n\n" -> "" -//@[no-compat] normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" -//@[no-compat] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[no-compat] rustc-env:RUST_BACKTRACE=0 #![allow(unreachable_code, unused)] @@ -47,4 +34,5 @@ struct StateContext<'a, TFsm: Fsm> { fn main() { let mut builder: FsmBuilder = todo!(); builder.state().on_entry(|_| {}); + //~^ ERROR the trait bound `usize: Fsm` is not satisfied } diff --git a/tests/ui/inline-const/const-expr-array-init.rs b/tests/ui/inline-const/const-expr-array-init.rs index 075c27c1cc92d..eb126b61f2dfe 100644 --- a/tests/ui/inline-const/const-expr-array-init.rs +++ b/tests/ui/inline-const/const-expr-array-init.rs @@ -1,7 +1,5 @@ //@ build-pass -#![feature(inline_const)] - use std::cell::Cell; fn main() { diff --git a/tests/ui/inline-const/const-expr-basic.rs b/tests/ui/inline-const/const-expr-basic.rs index 6a19cc656d02f..7f769d2b5c337 100644 --- a/tests/ui/inline-const/const-expr-basic.rs +++ b/tests/ui/inline-const/const-expr-basic.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - fn foo() -> i32 { const { let x = 5 + 10; diff --git a/tests/ui/inline-const/const-expr-generic-err.rs b/tests/ui/inline-const/const-expr-generic-err.rs index 3c4bbcb3dc9a6..3249e826a96be 100644 --- a/tests/ui/inline-const/const-expr-generic-err.rs +++ b/tests/ui/inline-const/const-expr-generic-err.rs @@ -1,5 +1,4 @@ //@ build-fail -#![feature(inline_const)] fn foo() { const { assert!(std::mem::size_of::() == 0); } //~ ERROR E0080 diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index 7331c7f18e976..dcd6b62bbfc1d 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -1,37 +1,37 @@ error[E0080]: evaluation of `foo::::{constant#0}` failed - --> $DIR/const-expr-generic-err.rs:5:13 + --> $DIR/const-expr-generic-err.rs:4:13 | LL | const { assert!(std::mem::size_of::() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::() == 0', $DIR/const-expr-generic-err.rs:5:13 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::() == 0', $DIR/const-expr-generic-err.rs:4:13 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:5:5 + --> $DIR/const-expr-generic-err.rs:4:5 | LL | const { assert!(std::mem::size_of::() == 0); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: the above error was encountered while instantiating `fn foo::` - --> $DIR/const-expr-generic-err.rs:13:5 + --> $DIR/const-expr-generic-err.rs:12:5 | LL | foo::(); | ^^^^^^^^^^^^ error[E0080]: evaluation of `bar::<0>::{constant#0}` failed - --> $DIR/const-expr-generic-err.rs:9:13 + --> $DIR/const-expr-generic-err.rs:8:13 | LL | const { N - 1 } | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:9:5 + --> $DIR/const-expr-generic-err.rs:8:5 | LL | const { N - 1 } | ^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:9:5 + --> $DIR/const-expr-generic-err.rs:8:5 | LL | const { N - 1 } | ^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | const { N - 1 } = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn bar::<0>` - --> $DIR/const-expr-generic-err.rs:14:5 + --> $DIR/const-expr-generic-err.rs:13:5 | LL | bar::<0>(); | ^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-expr-generic-err2.rs b/tests/ui/inline-const/const-expr-generic-err2.rs index e097cbe9dd6d1..49cbdbfda5da8 100644 --- a/tests/ui/inline-const/const-expr-generic-err2.rs +++ b/tests/ui/inline-const/const-expr-generic-err2.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - fn foo() { let _ = [0u8; const { std::mem::size_of::() }]; //~^ ERROR: constant expression depends on a generic parameter diff --git a/tests/ui/inline-const/const-expr-generic-err2.stderr b/tests/ui/inline-const/const-expr-generic-err2.stderr index 5876a6c9e198d..c6d77593c46ff 100644 --- a/tests/ui/inline-const/const-expr-generic-err2.stderr +++ b/tests/ui/inline-const/const-expr-generic-err2.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/const-expr-generic-err2.rs:4:19 + --> $DIR/const-expr-generic-err2.rs:2:19 | LL | let _ = [0u8; const { std::mem::size_of::() }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-expr-generic.rs b/tests/ui/inline-const/const-expr-generic.rs index e634e1d4a47f1..0c33b02d3a2e7 100644 --- a/tests/ui/inline-const/const-expr-generic.rs +++ b/tests/ui/inline-const/const-expr-generic.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(inline_const)] fn foo() -> usize { const { std::mem::size_of::() } diff --git a/tests/ui/inline-const/const-expr-inference.rs b/tests/ui/inline-const/const-expr-inference.rs index f3b97d3430efa..99cea3204a194 100644 --- a/tests/ui/inline-const/const-expr-inference.rs +++ b/tests/ui/inline-const/const-expr-inference.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - pub fn todo() -> T { const { todo!() } } diff --git a/tests/ui/inline-const/const-expr-lifetime-err.rs b/tests/ui/inline-const/const-expr-lifetime-err.rs index 0a032a7338ad0..df1e5fcb47352 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.rs +++ b/tests/ui/inline-const/const-expr-lifetime-err.rs @@ -1,5 +1,4 @@ #![feature(const_mut_refs)] -#![feature(inline_const)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/const-expr-lifetime-err.stderr b/tests/ui/inline-const/const-expr-lifetime-err.stderr index 75877bc093a79..f97e2d25e6c25 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.stderr +++ b/tests/ui/inline-const/const-expr-lifetime-err.stderr @@ -1,5 +1,5 @@ error[E0597]: `y` does not live long enough - --> $DIR/const-expr-lifetime-err.rs:23:30 + --> $DIR/const-expr-lifetime-err.rs:22:30 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/inline-const/const-expr-lifetime.rs b/tests/ui/inline-const/const-expr-lifetime.rs index 5dac17645d7a8..071e724a0faa3 100644 --- a/tests/ui/inline-const/const-expr-lifetime.rs +++ b/tests/ui/inline-const/const-expr-lifetime.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(const_mut_refs)] -#![feature(inline_const)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/const-expr-macro.rs b/tests/ui/inline-const/const-expr-macro.rs index bf3cb3c3320fb..cf07eb12f5a94 100644 --- a/tests/ui/inline-const/const-expr-macro.rs +++ b/tests/ui/inline-const/const-expr-macro.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - macro_rules! do_const_block{ ($val:block) => { const $val } } diff --git a/tests/ui/inline-const/const-expr-reference.rs b/tests/ui/inline-const/const-expr-reference.rs index b3753b0d371af..208271e37c311 100644 --- a/tests/ui/inline-const/const-expr-reference.rs +++ b/tests/ui/inline-const/const-expr-reference.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - const fn bar() -> i32 { const { 2 + 3 diff --git a/tests/ui/inline-const/const-match-pat-lifetime.rs b/tests/ui/inline-const/const-match-pat-lifetime.rs index f909e68e7be51..590c426c77379 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(const_mut_refs)] -#![feature(inline_const)] #![feature(inline_const_pat)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs index a1c3c61484ae6..e0a889ac34710 100644 --- a/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs +++ b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - fn main() { let _my_usize = const { let a = 10_usize; diff --git a/tests/ui/inline-const/expr-unsafe-err.rs b/tests/ui/inline-const/expr-unsafe-err.rs index a05a294516833..d53d84b944f0b 100644 --- a/tests/ui/inline-const/expr-unsafe-err.rs +++ b/tests/ui/inline-const/expr-unsafe-err.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] const unsafe fn require_unsafe() -> usize { 1 } diff --git a/tests/ui/inline-const/expr-unsafe-err.stderr b/tests/ui/inline-const/expr-unsafe-err.stderr index 45f850d1f99bf..13a408b971c8c 100644 --- a/tests/ui/inline-const/expr-unsafe-err.stderr +++ b/tests/ui/inline-const/expr-unsafe-err.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block - --> $DIR/expr-unsafe-err.rs:8:9 + --> $DIR/expr-unsafe-err.rs:7:9 | LL | require_unsafe(); | ^^^^^^^^^^^^^^^^ call to unsafe function diff --git a/tests/ui/inline-const/expr-unsafe.rs b/tests/ui/inline-const/expr-unsafe.rs index f9d1450503e2a..cdd101f3e0884 100644 --- a/tests/ui/inline-const/expr-unsafe.rs +++ b/tests/ui/inline-const/expr-unsafe.rs @@ -1,7 +1,7 @@ //@ check-pass #![warn(unused_unsafe)] -#![feature(inline_const)] + const unsafe fn require_unsafe() -> usize { 1 } fn main() { diff --git a/tests/ui/inline-const/expr-with-block-err.rs b/tests/ui/inline-const/expr-with-block-err.rs index f7547742ddcbe..6f85075755888 100644 --- a/tests/ui/inline-const/expr-with-block-err.rs +++ b/tests/ui/inline-const/expr-with-block-err.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - fn main() { const { 2 } - const { 1 }; //~^ ERROR mismatched types diff --git a/tests/ui/inline-const/expr-with-block-err.stderr b/tests/ui/inline-const/expr-with-block-err.stderr index a46d739504582..f127c11e9b7a5 100644 --- a/tests/ui/inline-const/expr-with-block-err.stderr +++ b/tests/ui/inline-const/expr-with-block-err.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/expr-with-block-err.rs:4:13 + --> $DIR/expr-with-block-err.rs:2:13 | LL | const { 2 } - const { 1 }; | ^ expected `()`, found integer diff --git a/tests/ui/inline-const/expr-with-block.rs b/tests/ui/inline-const/expr-with-block.rs index 07a1c9a10f5c2..a32afbcffaddd 100644 --- a/tests/ui/inline-const/expr-with-block.rs +++ b/tests/ui/inline-const/expr-with-block.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(inline_const)] + fn main() { match true { true => const {} diff --git a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs index e69106a43af49..c53aab60b06fa 100644 --- a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs +++ b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs @@ -1,8 +1,6 @@ //@ check-pass // issue: 114660 -#![feature(inline_const)] - fn main() { const { core::mem::transmute:: }; // Don't resolve the instance of this inline constant to be an intrinsic, diff --git a/tests/ui/inline-const/interpolated.rs b/tests/ui/inline-const/interpolated.rs index 582900e7aa012..38ed2a042e090 100644 --- a/tests/ui/inline-const/interpolated.rs +++ b/tests/ui/inline-const/interpolated.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - // This used to be unsupported since the parser first tries to check if we have // any nested items, and then checks for statements (and expressions). The heuristic // that we were using to detect the beginning of a const item was incorrect, so diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs index 242959c6b5164..2cfb8a0d19fc3 100644 --- a/tests/ui/inline-const/promotion.rs +++ b/tests/ui/inline-const/promotion.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![allow(arithmetic_overflow, unconditional_panic)] // The only way to have promoteds that fail is in `const fn` called from `const`/`static`. diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr index 7f06b97818bf5..4e914c9e08728 100644 --- a/tests/ui/inline-const/promotion.stderr +++ b/tests/ui/inline-const/promotion.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:17:37 + --> $DIR/promotion.rs:16:37 | LL | let _x: &'static i32 = &div_by_zero(); | ------------ ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/inline-const/required-const.rs b/tests/ui/inline-const/required-const.rs index 3de0ab2a0c06c..8f640e933d019 100644 --- a/tests/ui/inline-const/required-const.rs +++ b/tests/ui/inline-const/required-const.rs @@ -1,6 +1,5 @@ //@ build-fail //@ compile-flags: -Zmir-opt-level=3 -#![feature(inline_const)] fn foo() { if false { diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr index 2a13d18547c54..6ca4c250223e6 100644 --- a/tests/ui/inline-const/required-const.stderr +++ b/tests/ui/inline-const/required-const.stderr @@ -1,13 +1,13 @@ error[E0080]: evaluation of `foo::::{constant#0}` failed - --> $DIR/required-const.rs:7:17 + --> $DIR/required-const.rs:6:17 | LL | const { panic!() } - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/required-const.rs:7:17 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/required-const.rs:6:17 | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $DIR/required-const.rs:7:9 + --> $DIR/required-const.rs:6:9 | LL | const { panic!() } | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr index f6e5421f87845..9e2c19e90d596 100644 --- a/tests/ui/instrument-coverage/coverage-options.bad.stderr +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad` for unstable option `coverage-options` - either `no-branch`, `branch` or `mcdc` was expected +error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `mcdc` was expected diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 50c01ed29b5ec..332da32e435dc 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,20 +1,17 @@ //@ needs-profiler-support -//@ revisions: branch no-branch bad +//@ revisions: block branch bad //@ compile-flags -Cinstrument-coverage +//@ [block] check-pass +//@ [block] compile-flags: -Zcoverage-options=block + //@ [branch] check-pass //@ [branch] compile-flags: -Zcoverage-options=branch -//@ [no-branch] check-pass -//@ [no-branch] compile-flags: -Zcoverage-options=no-branch - //@ [mcdc] check-pass //@ [mcdc] compile-flags: -Zcoverage-options=mcdc //@ [bad] check-fail //@ [bad] compile-flags: -Zcoverage-options=bad -//@ [conflict] check-fail -//@ [conflict] compile-flags: -Zcoverage-options=no-branch,mcdc - fn main() {} diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs index fa9cbe4400cef..254ac24f0b941 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs @@ -16,7 +16,7 @@ use std::intrinsics; #[derive(Copy, Clone)] pub struct Foo(i64); -pub fn test_cttz(v: Foo) -> Foo { +pub fn test_cttz(v: Foo) -> u32 { intrinsics::cttz(v) //~^ ERROR `cttz` intrinsic: expected basic integer type, found `Foo` } diff --git a/tests/ui/intrinsics/intrinsics-integer.rs b/tests/ui/intrinsics/intrinsics-integer.rs index bfd7e4714fef8..7dbc4b8b7cece 100644 --- a/tests/ui/intrinsics/intrinsics-integer.rs +++ b/tests/ui/intrinsics/intrinsics-integer.rs @@ -6,13 +6,13 @@ mod rusti { extern "rust-intrinsic" { #[rustc_safe_intrinsic] - pub fn ctpop(x: T) -> T; + pub fn ctpop(x: T) -> u32; #[rustc_safe_intrinsic] - pub fn ctlz(x: T) -> T; - pub fn ctlz_nonzero(x: T) -> T; + pub fn ctlz(x: T) -> u32; + pub fn ctlz_nonzero(x: T) -> u32; #[rustc_safe_intrinsic] - pub fn cttz(x: T) -> T; - pub fn cttz_nonzero(x: T) -> T; + pub fn cttz(x: T) -> u32; + pub fn cttz_nonzero(x: T) -> u32; #[rustc_safe_intrinsic] pub fn bswap(x: T) -> T; #[rustc_safe_intrinsic] diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs index b1ac7528d584d..67b9832d60140 100644 --- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -7,7 +7,6 @@ // // This test checks panic emitted from `mem::{uninitialized,zeroed}`. #![allow(deprecated, invalid_value)] -#![feature(generic_nonzero)] #![feature(never_type)] use std::{ diff --git a/tests/ui/invalid-compile-flags/print.rs b/tests/ui/invalid-compile-flags/print.rs new file mode 100644 index 0000000000000..0d0a9d22750dd --- /dev/null +++ b/tests/ui/invalid-compile-flags/print.rs @@ -0,0 +1 @@ +//@ compile-flags: --print yyyy diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr new file mode 100644 index 0000000000000..0a032aabdfe8a --- /dev/null +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -0,0 +1,4 @@ +error: unknown print request: `yyyy` + | + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr index 988db0fb1fc4b..3c451a859e94c 100644 --- a/tests/ui/issues/issue-17385.stderr +++ b/tests/ui/issues/issue-17385.stderr @@ -12,7 +12,10 @@ note: if `X` implemented `Clone`, you could clone the value --> $DIR/issue-17385.rs:1:1 | LL | struct X(isize); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(foo); + | --- you could clone this value error[E0382]: use of moved value: `e` --> $DIR/issue-17385.rs:25:11 @@ -28,7 +31,10 @@ note: if `Enum` implemented `Clone`, you could clone the value --> $DIR/issue-17385.rs:3:1 | LL | enum Enum { - | ^^^^^^^^^ + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(e); + | - you could clone this value error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-22644.stderr b/tests/ui/issues/issue-22644.stderr index 0799e9ef11b14..7d8a0ff170a59 100644 --- a/tests/ui/issues/issue-22644.stderr +++ b/tests/ui/issues/issue-22644.stderr @@ -63,9 +63,9 @@ LL | 5); help: try comparing the cast value | LL ~ println!("{}", (a -LL | +LL | ... -LL | +LL | LL ~ usize) | diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs index d1a9e37251ee7..63c061594d87e 100644 --- a/tests/ui/issues/issue-24357.rs +++ b/tests/ui/issues/issue-24357.rs @@ -1,10 +1,12 @@ struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value +//~^ NOTE consider implementing `Clone` for this type fn main() { let x = NoCopy; //~^ NOTE move occurs because `x` has type `NoCopy` let f = move || { let y = x; }; //~^ NOTE value moved into closure here //~| NOTE variable moved due to use in closure + //~| NOTE you could clone this value let z = x; //~^ ERROR use of moved value: `x` //~| NOTE value used here after move diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr index 6d50eea7e21a0..2d85077fe4c21 100644 --- a/tests/ui/issues/issue-24357.stderr +++ b/tests/ui/issues/issue-24357.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/issue-24357.rs:8:12 + --> $DIR/issue-24357.rs:10:12 | LL | let x = NoCopy; | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait @@ -16,7 +16,10 @@ note: if `NoCopy` implemented `Clone`, you could clone the value --> $DIR/issue-24357.rs:1:1 | LL | struct NoCopy; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let f = move || { let y = x; }; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-43250.stderr b/tests/ui/issues/issue-43250.stderr index f729c5cf10cea..e74342b85adb3 100644 --- a/tests/ui/issues/issue-43250.stderr +++ b/tests/ui/issues/issue-43250.stderr @@ -3,12 +3,16 @@ error: arbitrary expressions aren't allowed in patterns | LL | m!(y); | ^ + | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression error: arbitrary expressions aren't allowed in patterns --> $DIR/issue-43250.rs:11:8 | LL | m!(C); | ^ + | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr index 8b4aff54dc3c0..14b5cfa9f9ac4 100644 --- a/tests/ui/issues/issue-4335.stderr +++ b/tests/ui/issues/issue-4335.stderr @@ -7,6 +7,14 @@ LL | id(Box::new(|| *v)) | -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait | | | captured by this `FnMut` closure + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-4335.rs:5:10 + | +LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { + | ^ consider constraining this type parameter with `Clone` +LL | id(Box::new(|| *v)) + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-56806.stderr b/tests/ui/issues/issue-56806.stderr index f3d4c2fef94e2..ec50d863758db 100644 --- a/tests/ui/issues/issue-56806.stderr +++ b/tests/ui/issues/issue-56806.stderr @@ -1,4 +1,4 @@ -error[E0307]: invalid `self` parameter type: Box<(dyn Trait + 'static)> +error[E0307]: invalid `self` parameter type: `Box<(dyn Trait + 'static)>` --> $DIR/issue-56806.rs:2:34 | LL | fn dyn_instead_of_self(self: Box); diff --git a/tests/ui/issues/issue-64593.rs b/tests/ui/issues/issue-64593.rs index 091c3a2f316dd..e28b9577347be 100644 --- a/tests/ui/issues/issue-64593.rs +++ b/tests/ui/issues/issue-64593.rs @@ -1,6 +1,5 @@ //@ check-pass #![deny(improper_ctypes)] -#![feature(generic_nonzero)] pub struct Error(std::num::NonZero); diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs index 835fdfae86c03..6d1d9f5e3a994 100644 --- a/tests/ui/issues/issue-66706.rs +++ b/tests/ui/issues/issue-66706.rs @@ -12,6 +12,7 @@ fn b() { fn c() { [0; [|&_: _ &_| {}; 0 ].len()] //~^ ERROR expected `,`, found `&` + //~| ERROR type annotations needed } fn d() { diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index ffdd61e7723be..0271db754bd33 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -21,7 +21,7 @@ LL | [0; [|&_: _ &_| {}; 0 ].len()] | help: missing `,` error: expected identifier, found reserved identifier `_` - --> $DIR/issue-66706.rs:18:26 + --> $DIR/issue-66706.rs:19:26 | LL | [0; match [|f @ &ref _| () ] {} ] | ----- ^ expected identifier, found reserved identifier @@ -34,6 +34,12 @@ error[E0282]: type annotations needed LL | [0; [|_: _ &_| ()].len()] | ^ cannot infer type -error: aborting due to 5 previous errors +error[E0282]: type annotations needed + --> $DIR/issue-66706.rs:13:11 + | +LL | [0; [|&_: _ &_| {}; 0 ].len()] + | ^^^^^ cannot infer type + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs index e98affc5cc299..2c5257ce063cb 100644 --- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; - //~^ constant } diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index 6f9302bc4a549..fa1d7dffbd49a 100644 --- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,12 +13,6 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -note: erroneous constant encountered - --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 - | -LL | let _ = [0; B::VALUE]; - | ^^^^^^^^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0046, E0437. diff --git a/tests/ui/lang-items/issue-83471.rs b/tests/ui/lang-items/issue-83471.rs index b32aa03415152..6be345ac50765 100644 --- a/tests/ui/lang-items/issue-83471.rs +++ b/tests/ui/lang-items/issue-83471.rs @@ -5,12 +5,12 @@ #![no_core] #[lang = "sized"] -//~^ ERROR: language items are subject to change [E0658] +//~^ ERROR: lang items are subject to change [E0658] trait Sized {} #[lang = "fn"] -//~^ ERROR: language items are subject to change [E0658] -//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument +//~^ ERROR: lang items are subject to change [E0658] +//~| ERROR: `fn` lang item must be applied to a trait with 1 generic argument trait Fn { fn call(export_name); //~^ ERROR: expected type diff --git a/tests/ui/lang-items/issue-83471.stderr b/tests/ui/lang-items/issue-83471.stderr index 1f22d966dd7d7..244b2efeaf1e0 100644 --- a/tests/ui/lang-items/issue-83471.stderr +++ b/tests/ui/lang-items/issue-83471.stderr @@ -4,7 +4,7 @@ error[E0573]: expected type, found built-in attribute `export_name` LL | fn call(export_name); | ^^^^^^^^^^^ not a type -error[E0658]: language items are subject to change +error[E0658]: lang items are subject to change --> $DIR/issue-83471.rs:7:1 | LL | #[lang = "sized"] @@ -13,7 +13,7 @@ LL | #[lang = "sized"] = help: add `#![feature(lang_items)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: language items are subject to change +error[E0658]: lang items are subject to change --> $DIR/issue-83471.rs:11:1 | LL | #[lang = "fn"] @@ -32,7 +32,7 @@ LL | fn call(export_name); = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error[E0718]: `fn` language item must be applied to a trait with 1 generic argument +error[E0718]: `fn` lang item must be applied to a trait with 1 generic argument --> $DIR/issue-83471.rs:11:1 | LL | #[lang = "fn"] diff --git a/tests/ui/lang-items/issue-87573.rs b/tests/ui/lang-items/issue-87573.rs index aeb0c245a72ec..7b805e8b0cdb6 100644 --- a/tests/ui/lang-items/issue-87573.rs +++ b/tests/ui/lang-items/issue-87573.rs @@ -18,11 +18,11 @@ trait Sync {} impl Sync for bool {} #[lang = "drop_in_place"] -//~^ ERROR: `drop_in_place` language item must be applied to a function with at least 1 generic argument +//~^ ERROR: `drop_in_place` lang item must be applied to a function with at least 1 generic argument fn drop_fn() { while false {} } #[lang = "start"] -//~^ ERROR: `start` language item must be applied to a function with 1 generic argument +//~^ ERROR: `start` lang item must be applied to a function with 1 generic argument fn start(){} diff --git a/tests/ui/lang-items/issue-87573.stderr b/tests/ui/lang-items/issue-87573.stderr index 25560cfa0e6c7..7085bb8c339d4 100644 --- a/tests/ui/lang-items/issue-87573.stderr +++ b/tests/ui/lang-items/issue-87573.stderr @@ -1,4 +1,4 @@ -error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument +error[E0718]: `drop_in_place` lang item must be applied to a function with at least 1 generic argument --> $DIR/issue-87573.rs:20:1 | LL | #[lang = "drop_in_place"] @@ -7,7 +7,7 @@ LL | LL | fn drop_fn() { | - this function has 0 generic arguments -error[E0718]: `start` language item must be applied to a function with 1 generic argument +error[E0718]: `start` lang item must be applied to a function with 1 generic argument --> $DIR/issue-87573.rs:26:1 | LL | #[lang = "start"] diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 697790023d6c9..0f982df61e8e7 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -9,30 +9,30 @@ trait MySized {} #[lang = "add"] trait MyAdd<'a, T> {} -//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718] +//~^^ ERROR: `add` lang item must be applied to a trait with 1 generic argument [E0718] #[lang = "drop_in_place"] -//~^ ERROR `drop_in_place` language item must be applied to a function with at least 1 generic +//~^ ERROR `drop_in_place` lang item must be applied to a function with at least 1 generic fn my_ptr_drop() {} #[lang = "index"] trait MyIndex<'a, T> {} -//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718] +//~^^ ERROR: `index` lang item must be applied to a trait with 1 generic argument [E0718] #[lang = "phantom_data"] -//~^ ERROR `phantom_data` language item must be applied to a struct with 1 generic argument +//~^ ERROR `phantom_data` lang item must be applied to a struct with 1 generic argument struct MyPhantomData; //~^ ERROR `T` is never used //~| ERROR `U` is never used #[lang = "owned_box"] -//~^ ERROR `owned_box` language item must be applied to a struct with at least 1 generic argument +//~^ ERROR `owned_box` lang item must be applied to a struct with at least 1 generic argument struct Foo; // When the `start` lang item is missing generics very odd things can happen, especially when // it comes to cross-crate monomorphization #[lang = "start"] -//~^ ERROR `start` language item must be applied to a function with 1 generic argument [E0718] +//~^ ERROR `start` lang item must be applied to a function with 1 generic argument [E0718] fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { 0 } diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 30abdf84046ea..3de67d6594035 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -1,4 +1,4 @@ -error[E0718]: `add` language item must be applied to a trait with 1 generic argument +error[E0718]: `add` lang item must be applied to a trait with 1 generic argument --> $DIR/lang-item-generic-requirements.rs:10:1 | LL | #[lang = "add"] @@ -6,7 +6,7 @@ LL | #[lang = "add"] LL | trait MyAdd<'a, T> {} | ------- this trait has 2 generic arguments -error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument +error[E0718]: `drop_in_place` lang item must be applied to a function with at least 1 generic argument --> $DIR/lang-item-generic-requirements.rs:14:1 | LL | #[lang = "drop_in_place"] @@ -15,7 +15,7 @@ LL | LL | fn my_ptr_drop() {} | - this function has 0 generic arguments -error[E0718]: `index` language item must be applied to a trait with 1 generic argument +error[E0718]: `index` lang item must be applied to a trait with 1 generic argument --> $DIR/lang-item-generic-requirements.rs:18:1 | LL | #[lang = "index"] @@ -23,7 +23,7 @@ LL | #[lang = "index"] LL | trait MyIndex<'a, T> {} | ------- this trait has 2 generic arguments -error[E0718]: `phantom_data` language item must be applied to a struct with 1 generic argument +error[E0718]: `phantom_data` lang item must be applied to a struct with 1 generic argument --> $DIR/lang-item-generic-requirements.rs:22:1 | LL | #[lang = "phantom_data"] @@ -32,7 +32,7 @@ LL | LL | struct MyPhantomData; | ------ this struct has 2 generic arguments -error[E0718]: `owned_box` language item must be applied to a struct with at least 1 generic argument +error[E0718]: `owned_box` lang item must be applied to a struct with at least 1 generic argument --> $DIR/lang-item-generic-requirements.rs:28:1 | LL | #[lang = "owned_box"] @@ -41,7 +41,7 @@ LL | LL | struct Foo; | - this struct has 0 generic arguments -error[E0718]: `start` language item must be applied to a function with 1 generic argument +error[E0718]: `start` lang item must be applied to a function with 1 generic argument --> $DIR/lang-item-generic-requirements.rs:34:1 | LL | #[lang = "start"] diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs index 4717304c5c6b8..eb712ba409259 100644 --- a/tests/ui/lang-items/start_lang_item_with_target_feature.rs +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs @@ -11,7 +11,7 @@ pub trait Sized {} #[lang = "start"] #[target_feature(enable = "avx2")] -//~^ ERROR `start` language item function is not allowed to have `#[target_feature]` +//~^ ERROR `start` lang item function is not allowed to have `#[target_feature]` fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { 0 } diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr index bb0583dfde056..6214e3f8bc79a 100644 --- a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr +++ b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr @@ -1,11 +1,11 @@ -error: `start` language item function is not allowed to have `#[target_feature]` +error: `start` lang item function is not allowed to have `#[target_feature]` --> $DIR/start_lang_item_with_target_feature.rs:13:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ------------------------------------------------------------------------------------------- `start` language item function is not allowed to have `#[target_feature]` + | ------------------------------------------------------------------------------------------- `start` lang item function is not allowed to have `#[target_feature]` error: aborting due to 1 previous error diff --git a/tests/crashes/124031.rs b/tests/ui/layout/ice-type-error-in-tail-124031.rs similarity index 54% rename from tests/crashes/124031.rs rename to tests/ui/layout/ice-type-error-in-tail-124031.rs index bdc66fbafe4ca..0a2be11740358 100644 --- a/tests/crashes/124031.rs +++ b/tests/ui/layout/ice-type-error-in-tail-124031.rs @@ -1,10 +1,13 @@ -//@ known-bug: #124031 +// Regression test for issue #124031 +// Checks that we don't ICE when the tail +// of an ADT has a type error trait Trait { type RefTarget; } impl Trait for () {} +//~^ ERROR not all trait items implemented, missing: `RefTarget` struct Other { data: <() as Trait>::RefTarget, diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.stderr b/tests/ui/layout/ice-type-error-in-tail-124031.stderr new file mode 100644 index 0000000000000..57dc83f92dfda --- /dev/null +++ b/tests/ui/layout/ice-type-error-in-tail-124031.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `RefTarget` + --> $DIR/ice-type-error-in-tail-124031.rs:9:1 + | +LL | type RefTarget; + | -------------- `RefTarget` from trait +... +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/layout/unsafe-cell-hides-niche.rs b/tests/ui/layout/unsafe-cell-hides-niche.rs index 568eb819be2e6..fe51c9925e802 100644 --- a/tests/ui/layout/unsafe-cell-hides-niche.rs +++ b/tests/ui/layout/unsafe-cell-hides-niche.rs @@ -6,7 +6,6 @@ //@ check-pass //@ compile-flags: --crate-type=lib //@ only-x86 -#![feature(generic_nonzero)] #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs index 058f59234878f..0c37c0f010e2b 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.rs +++ b/tests/ui/layout/zero-sized-array-enum-niche.rs @@ -1,6 +1,5 @@ //@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" #![crate_type = "lib"] -#![feature(generic_nonzero)] #![feature(rustc_attrs)] // Various tests around the behavior of zero-sized arrays and diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index af049125de467..ee34cfdfb0db0 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -98,7 +98,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:14:1 + --> $DIR/zero-sized-array-enum-niche.rs:13:1 | LL | type AlignedResult = Result<[u32; 0], bool>; | ^^^^^^^^^^^^^^^^^^ @@ -227,7 +227,7 @@ error: layout_of(MultipleAlignments) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:22:1 + --> $DIR/zero-sized-array-enum-niche.rs:21:1 | LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -332,7 +332,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:38:1 + --> $DIR/zero-sized-array-enum-niche.rs:37:1 | LL | type NicheLosesToTagged = Result<[u32; 0], Packed>>; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -441,7 +441,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:45:1 + --> $DIR/zero-sized-array-enum-niche.rs:44:1 | LL | type NicheWinsOverTagged = Result<[u32; 0], Packed>; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr index d99ea6a0c309f..d6da842e6abae 100644 --- a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr +++ b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here | LL | fn bar(foo: Foo) {} | ^^^^^^^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | fn bar(foo: Foo) {} + | ~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index a2461cff93265..3bc87b9d480b4 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - struct S<'a>(&'a u8); fn foo() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 320e64a2f7744..2857fc72ea140 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/unusual-rib-combinations.rs:24:15 + --> $DIR/unusual-rib-combinations.rs:22:15 | LL | fn d() {} | ^ expected named lifetime parameter error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/unusual-rib-combinations.rs:29:22 + --> $DIR/unusual-rib-combinations.rs:27:22 | LL | struct Bar Foo<'a>)>; | ^^ the type must not depend on the parameter `'a` @@ -13,25 +13,25 @@ LL | struct Bar Foo<'a>)>; = note: lifetime parameters may not be used in the type of const parameters error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:7:16 + --> $DIR/unusual-rib-combinations.rs:5:16 | LL | fn a() -> [u8; foo::()] { | ^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:14:15 + --> $DIR/unusual-rib-combinations.rs:12:15 | LL | fn b() {} | ^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:18:10 + --> $DIR/unusual-rib-combinations.rs:16:10 | LL | fn c() {} | ^^^^ only `Fn` traits may use parentheses error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/unusual-rib-combinations.rs:18:6 + --> $DIR/unusual-rib-combinations.rs:16:6 | LL | fn c() {} | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | fn c() {} = note: `#[deny(invalid_type_param_default)]` on by default error[E0308]: mismatched types - --> $DIR/unusual-rib-combinations.rs:7:16 + --> $DIR/unusual-rib-combinations.rs:5:16 | LL | fn a() -> [u8; foo::()] { | ^^^^^^^ expected `usize`, found fn item @@ -50,7 +50,7 @@ LL | fn a() -> [u8; foo::()] { found fn item `fn() {foo}` error: `S<'_>` is forbidden as the type of a const generic parameter - --> $DIR/unusual-rib-combinations.rs:24:15 + --> $DIR/unusual-rib-combinations.rs:22:15 | LL | fn d() {} | ^ diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index cb63af0ea4228..728dfabb393e0 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -2,7 +2,6 @@ //@ aux-build:external_extern_fn.rs #![crate_type = "lib"] #![warn(clashing_extern_declarations)] -#![feature(generic_nonzero)] mod redeclared_different_signature { mod a { diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 86ee789aeb22d..43c8cdead9f41 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:430:55 + --> $DIR/clashing-extern-fn.rs:429:55 | LL | fn hidden_niche_transparent_no_niche() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -9,7 +9,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:434:46 + --> $DIR/clashing-extern-fn.rs:433:46 | LL | fn hidden_niche_unsafe_cell() -> Option>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -18,7 +18,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:15:13 + --> $DIR/clashing-extern-fn.rs:14:13 | LL | fn clash(x: u8); | --------------- `clash` previously declared here @@ -35,7 +35,7 @@ LL | #![warn(clashing_extern_declarations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:53:9 + --> $DIR/clashing-extern-fn.rs:52:9 | LL | #[link_name = "extern_link_name"] | --------------------------------- `extern_link_name` previously declared here @@ -47,7 +47,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:56:9 + --> $DIR/clashing-extern-fn.rs:55:9 | LL | fn some_other_new_name(x: i16); | ------------------------------ `some_other_new_name` previously declared here @@ -59,7 +59,7 @@ LL | #[link_name = "some_other_new_name"] found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:60:9 + --> $DIR/clashing-extern-fn.rs:59:9 | LL | #[link_name = "link_name_same"] | ------------------------------- `link_name_same` previously declared here @@ -71,7 +71,7 @@ LL | #[link_name = "link_name_same"] found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:73:9 + --> $DIR/clashing-extern-fn.rs:72:9 | LL | fn different_mod(x: u8); | ----------------------- `different_mod` previously declared here @@ -83,7 +83,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:83:9 + --> $DIR/clashing-extern-fn.rs:82:9 | LL | fn variadic_decl(x: u8, ...); | ---------------------------- `variadic_decl` previously declared here @@ -95,7 +95,7 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:143:13 + --> $DIR/clashing-extern-fn.rs:142:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | -------------------------------------------- `weigh_banana` previously declared here @@ -107,7 +107,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64; found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:172:13 + --> $DIR/clashing-extern-fn.rs:171:13 | LL | fn draw_point(p: Point); | ----------------------- `draw_point` previously declared here @@ -119,7 +119,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:198:13 + --> $DIR/clashing-extern-fn.rs:197:13 | LL | fn origin() -> Point3; | --------------------- `origin` previously declared here @@ -131,7 +131,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:221:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | ------------------------------- `transparent_incorrect` previously declared here @@ -143,7 +143,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:260:13 + --> $DIR/clashing-extern-fn.rs:259:13 | LL | fn missing_return_type() -> usize; | --------------------------------- `missing_return_type` previously declared here @@ -155,7 +155,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:278:13 + --> $DIR/clashing-extern-fn.rs:277:13 | LL | fn non_zero_usize() -> core::num::NonZero; | ------------------------------------------------ `non_zero_usize` previously declared here @@ -167,7 +167,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:280:13 + --> $DIR/clashing-extern-fn.rs:279:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ---------------------------------------------- `non_null_ptr` previously declared here @@ -179,7 +179,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:374:13 + --> $DIR/clashing-extern-fn.rs:373:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -191,7 +191,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:376:13 + --> $DIR/clashing-extern-fn.rs:375:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -203,7 +203,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:430:13 + --> $DIR/clashing-extern-fn.rs:429:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here @@ -215,7 +215,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option Option` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:434:13 + --> $DIR/clashing-extern-fn.rs:433:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | -------------------------------------- `hidden_niche_unsafe_cell` previously declared here diff --git a/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.rs b/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.rs new file mode 100644 index 0000000000000..2b93d0f8a609d --- /dev/null +++ b/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.rs @@ -0,0 +1,22 @@ +// Regression test for issue 123710. +// Tests that the we do not ICE in KnownPanicsLint +// when a union contains an enum with an repr(packed), +// which is a repr not supported for enums + +#[repr(packed)] +//~^ ERROR attribute should be applied to a struct or union +#[repr(u32)] +enum E { + A, + B, + C, +} + +fn main() { + union InvalidTag { + int: u32, + e: E, +//~^ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + } + let _invalid_tag = InvalidTag { int: 4 }; +} diff --git a/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.stderr b/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.stderr new file mode 100644 index 0000000000000..44dde6120e8d6 --- /dev/null +++ b/tests/ui/lint/ice-const-prop-unions-known-panics-lint-123710.stderr @@ -0,0 +1,29 @@ +error[E0517]: attribute should be applied to a struct or union + --> $DIR/ice-const-prop-unions-known-panics-lint-123710.rs:6:8 + | +LL | #[repr(packed)] + | ^^^^^^ +... +LL | / enum E { +LL | | A, +LL | | B, +LL | | C, +LL | | } + | |_- not a struct or union + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/ice-const-prop-unions-known-panics-lint-123710.rs:18:9 + | +LL | e: E, + | ^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | e: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0517, E0740. +For more information about an error, try `rustc --explain E0517`. diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index e87afe9094cab..2d1822a54ac33 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(inline_const)] #![feature(concat_bytes)] #![warn(invalid_from_utf8_unchecked)] diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 884165d4f123c..07616e118010b 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,5 +1,5 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:21:9 + --> $DIR/invalid_from_utf8.rs:20:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -7,13 +7,13 @@ LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112 | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:6:9 + --> $DIR/invalid_from_utf8.rs:5:9 | LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:23:9 + --> $DIR/invalid_from_utf8.rs:22:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -21,7 +21,7 @@ LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:41:9 + --> $DIR/invalid_from_utf8.rs:40:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -29,7 +29,7 @@ LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:43:9 + --> $DIR/invalid_from_utf8.rs:42:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -37,7 +37,7 @@ LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:45:9 + --> $DIR/invalid_from_utf8.rs:44:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -45,7 +45,7 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:47:9 + --> $DIR/invalid_from_utf8.rs:46:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -53,7 +53,7 @@ LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:64:9 + --> $DIR/invalid_from_utf8.rs:63:9 | LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -61,13 +61,13 @@ LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:7:9 + --> $DIR/invalid_from_utf8.rs:6:9 | LL | #![warn(invalid_from_utf8)] | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:66:9 + --> $DIR/invalid_from_utf8.rs:65:9 | LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -75,7 +75,7 @@ LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:84:9 + --> $DIR/invalid_from_utf8.rs:83:9 | LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -83,7 +83,7 @@ LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:86:9 + --> $DIR/invalid_from_utf8.rs:85:9 | LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -91,7 +91,7 @@ LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']) | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:88:9 + --> $DIR/invalid_from_utf8.rs:87:9 | LL | std::str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^-------------^ @@ -99,7 +99,7 @@ LL | std::str::from_utf8(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:90:9 + --> $DIR/invalid_from_utf8.rs:89:9 | LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -107,7 +107,7 @@ LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:97:5 + --> $DIR/invalid_from_utf8.rs:96:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -115,7 +115,7 @@ LL | std::str::from_utf8_mut(&mut a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:101:5 + --> $DIR/invalid_from_utf8.rs:100:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -124,7 +124,7 @@ LL | std::str::from_utf8_mut(c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:104:5 + --> $DIR/invalid_from_utf8.rs:103:5 | LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -132,7 +132,7 @@ LL | std::str::from_utf8(c); | ^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:107:5 + --> $DIR/invalid_from_utf8.rs:106:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -140,7 +140,7 @@ LL | std::str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:110:5 + --> $DIR/invalid_from_utf8.rs:109:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -148,7 +148,7 @@ LL | std::str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:113:5 + --> $DIR/invalid_from_utf8.rs:112:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -156,7 +156,7 @@ LL | std::str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:116:5 + --> $DIR/invalid_from_utf8.rs:115:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes diff --git a/tests/ui/lint/invalid_value.rs b/tests/ui/lint/invalid_value.rs index 1d2f23aaaf6f5..29e8e6cfef6dd 100644 --- a/tests/ui/lint/invalid_value.rs +++ b/tests/ui/lint/invalid_value.rs @@ -2,7 +2,7 @@ // in a lint. #![allow(deprecated)] #![deny(invalid_value)] -#![feature(generic_nonzero, never_type, rustc_attrs)] +#![feature(never_type, rustc_attrs)] use std::mem::{self, MaybeUninit}; use std::ptr::NonNull; diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 3157b6e240aec..c60290f8553a7 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] #![deny(improper_ctypes)] -#![feature(generic_nonzero)] #![feature(ptr_internals)] #![feature(transparent_unions)] diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 48be3eb5a5630..103fda8d40253 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `U`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:61:13 + --> $DIR/lint-ctypes-enum.rs:60:13 | LL | fn uf(x: U); | ^ not FFI-safe @@ -7,7 +7,7 @@ LL | fn uf(x: U); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:10:1 + --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum U { | ^^^^^^ @@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `B`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:62:13 + --> $DIR/lint-ctypes-enum.rs:61:13 | LL | fn bf(x: B); | ^ not FFI-safe @@ -26,13 +26,13 @@ LL | fn bf(x: B); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:13:1 + --> $DIR/lint-ctypes-enum.rs:12:1 | LL | enum B { | ^^^^^^ error: `extern` block uses type `T`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:63:13 + --> $DIR/lint-ctypes-enum.rs:62:13 | LL | fn tf(x: T); | ^ not FFI-safe @@ -40,13 +40,13 @@ LL | fn tf(x: T); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:17:1 + --> $DIR/lint-ctypes-enum.rs:16:1 | LL | enum T { | ^^^^^^ error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:75:23 + --> $DIR/lint-ctypes-enum.rs:74:23 | LL | fn nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -54,7 +54,7 @@ LL | fn nonzero_u128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:82:23 + --> $DIR/lint-ctypes-enum.rs:81:23 | LL | fn nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -62,7 +62,7 @@ LL | fn nonzero_i128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:87:28 + --> $DIR/lint-ctypes-enum.rs:86:28 | LL | fn transparent_union(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -71,7 +71,7 @@ LL | fn transparent_union(x: Option>>); = note: enum has no representation hint error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:89:20 + --> $DIR/lint-ctypes-enum.rs:88:20 | LL | fn repr_rust(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -80,7 +80,7 @@ LL | fn repr_rust(x: Option>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), NonZero>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:90:20 + --> $DIR/lint-ctypes-enum.rs:89:20 | LL | fn no_result(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.stderr b/tests/ui/lint/lint-pre-expansion-extern-module.stderr index 8a6e1531d5fdb..32c76da98b525 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.stderr +++ b/tests/ui/lint/lint-pre-expansion-extern-module.stderr @@ -6,8 +6,8 @@ LL | pub fn try() {} | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 - = note: `-W keyword-idents` implied by `-W rust-2018-compatibility` - = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents)]` + = note: `-W keyword-idents-2018` implied by `-W rust-2018-compatibility` + = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents_2018)]` warning: 1 warning emitted diff --git a/tests/ui/lint/must_not_suspend/tuple-mismatch.rs b/tests/ui/lint/must_not_suspend/tuple-mismatch.rs index 2f3c5d9ea294d..ec409925d7248 100644 --- a/tests/ui/lint/must_not_suspend/tuple-mismatch.rs +++ b/tests/ui/lint/must_not_suspend/tuple-mismatch.rs @@ -1,7 +1,8 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _coroutine = || { + let _coroutine = #[coroutine] + || { yield ((), ((), ())); yield ((), ()); //~^ ERROR mismatched types diff --git a/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr b/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr index 3adf26cfee229..102eadd7affd4 100644 --- a/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr +++ b/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/tuple-mismatch.rs:6:20 + --> $DIR/tuple-mismatch.rs:7:20 | LL | yield ((), ()); | ^^ expected `((), ())`, found `()` diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs index 2652447dcf59b..d8a497e43e502 100644 --- a/tests/ui/lint/non-local-defs/consts.rs +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -2,8 +2,6 @@ //@ edition:2021 //@ rustc-env:CARGO_CRATE_NAME=non_local_def -#![feature(inline_const)] - struct Test; trait Uto {} diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 5563ea9d93f06..d15b452b004e9 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:15:5 + --> $DIR/consts.rs:13:5 | LL | const Z: () = { | - help: use a const-anon item to suppress this lint: `_` @@ -14,7 +14,7 @@ LL | impl Uto for &Test {} = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:26:5 + --> $DIR/consts.rs:24:5 | LL | impl Uto2 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | impl Uto2 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:34:5 + --> $DIR/consts.rs:32:5 | LL | impl Uto3 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | impl Uto3 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:45:5 + --> $DIR/consts.rs:43:5 | LL | / impl Test { LL | | @@ -50,7 +50,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:52:9 + --> $DIR/consts.rs:50:9 | LL | / impl Test { LL | | @@ -64,7 +64,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:61:9 + --> $DIR/consts.rs:59:9 | LL | / impl Test { LL | | @@ -78,7 +78,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:74:9 + --> $DIR/consts.rs:72:9 | LL | impl Uto9 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | impl Uto9 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:81:9 + --> $DIR/consts.rs:79:9 | LL | impl Uto10 for Test {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs index 0ab3a6b198874..fea9679d7375d 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.rs +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![feature(inline_const)] - struct Cat; struct Wrap(T); diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index bd592a721572e..0cd385049aa6e 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:10:5 + --> $DIR/from-local-for-global.rs:8:5 | LL | / impl From for () { LL | | @@ -16,7 +16,7 @@ LL | | } = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:20:5 + --> $DIR/from-local-for-global.rs:18:5 | LL | / impl From>> for () { LL | | @@ -32,7 +32,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:34:5 + --> $DIR/from-local-for-global.rs:32:5 | LL | impl StillNonLocal for &Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | impl StillNonLocal for &Foo {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:42:5 + --> $DIR/from-local-for-global.rs:40:5 | LL | / impl From for GlobalSameFunction { LL | | @@ -59,7 +59,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:50:5 + --> $DIR/from-local-for-global.rs:48:5 | LL | / impl From for GlobalSameFunction { LL | | diff --git a/tests/ui/lint/non-local-defs/module_as_local.rs b/tests/ui/lint/non-local-defs/module_as_local.rs new file mode 100644 index 0000000000000..bb215026c7d40 --- /dev/null +++ b/tests/ui/lint/non-local-defs/module_as_local.rs @@ -0,0 +1,38 @@ +//! This test checks that module are treated as if they were local +//! +//! https://github.com/rust-lang/rust/issues/124396 + +//@ check-pass + +trait JoinTo {} + +fn simple_one() { + mod posts { + #[allow(non_camel_case_types)] + pub struct table {} + } + + impl JoinTo for posts::table {} +} + +fn simple_two() { + mod posts { + pub mod posts { + #[allow(non_camel_case_types)] + pub struct table {} + } + } + + impl JoinTo for posts::posts::table {} +} + +struct Global; +fn trait_() { + mod posts { + pub trait AdjecentTo {} + } + + impl posts::AdjecentTo for Global {} +} + +fn main() {} diff --git a/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs b/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs index c5dd281cb4e5f..12e2bcb898cad 100644 --- a/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs +++ b/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs @@ -1,12 +1,12 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![deny(unused_braces, unused_parens)] use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut x = |_| { + let mut x = #[coroutine] |_| { while let Some(_) = (yield) {} while let Some(_) = {yield} {} diff --git a/tests/ui/lint/unused/unused-closure.rs b/tests/ui/lint/unused/unused-closure.rs index 9106edee65380..4633038cc9bb3 100644 --- a/tests/ui/lint/unused/unused-closure.rs +++ b/tests/ui/lint/unused/unused-closure.rs @@ -2,7 +2,7 @@ //@ edition:2018 #![feature(async_closure)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![deny(unused_must_use)] fn unused() { @@ -26,7 +26,7 @@ fn unused() { fn ignored() { let _ = || {}; - let _ = || yield 42; + let _ = #[coroutine] || yield 42; } fn main() { diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs index ba32fb566e83b..0f9eac93930bc 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs @@ -20,10 +20,10 @@ fn doc_comment_between_if_else(num: u8) -> bool { } fn doc_comment_on_expr(num: u8) -> bool { - /// useless doc comment + (/// useless doc comment //~^ ERROR: attributes on expressions are experimental //~| ERROR: unused doc comment - num == 3 + num) == 3 } fn doc_comment_on_expr_field() -> bool { diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 55e4834e6707a..add85b2f5e043 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -5,10 +5,10 @@ LL | else { | ^^^^ expected expression error[E0658]: attributes on expressions are experimental - --> $DIR/unused-doc-comments-edge-cases.rs:23:5 + --> $DIR/unused-doc-comments-edge-cases.rs:23:6 | -LL | /// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | (/// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable @@ -32,12 +32,12 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/unused-doc-comments-edge-cases.rs:23:5 + --> $DIR/unused-doc-comments-edge-cases.rs:23:6 | -LL | /// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | (/// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | num == 3 +LL | num) == 3 | --- rustdoc does not generate documentation for expressions | = help: use `//` for a plain comment diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index 16fb1682d4a69..acc36550642d6 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -384,7 +384,7 @@ mod foo { \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m let x: Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m diff --git a/tests/ui/liveness/liveness-upvars.rs b/tests/ui/liveness/liveness-upvars.rs index 7898b97888230..f76efba3e6b3a 100644 --- a/tests/ui/liveness/liveness-upvars.rs +++ b/tests/ui/liveness/liveness-upvars.rs @@ -1,6 +1,6 @@ //@ edition:2018 //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![warn(unused)] #![allow(unreachable_code)] @@ -131,7 +131,7 @@ pub fn async_coroutine() { pub fn coroutine() { let mut s: u32 = 0; - let _ = |_| { + let _ = #[coroutine] |_| { s = 0; yield (); s = 1; //~ WARN value assigned to `s` is never read diff --git a/tests/ui/loops/dont-suggest-break-thru-item.rs b/tests/ui/loops/dont-suggest-break-thru-item.rs index 34a9a57bfed05..b4262ec02bf47 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.rs +++ b/tests/ui/loops/dont-suggest-break-thru-item.rs @@ -1,7 +1,5 @@ //@ edition:2021 -#![feature(inline_const)] - fn closure() { loop { let closure = || { diff --git a/tests/ui/loops/dont-suggest-break-thru-item.stderr b/tests/ui/loops/dont-suggest-break-thru-item.stderr index c84a98198f55a..642578ade60bf 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.stderr +++ b/tests/ui/loops/dont-suggest-break-thru-item.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:9:17 + --> $DIR/dont-suggest-break-thru-item.rs:7:17 | LL | / if true { LL | | Err(1) @@ -17,7 +17,7 @@ LL | return Err(1); | ++++++ + error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:23:17 + --> $DIR/dont-suggest-break-thru-item.rs:21:17 | LL | / if true { LL | | Err(1) @@ -35,7 +35,7 @@ LL | return Err(1); | ++++++ + error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:37:17 + --> $DIR/dont-suggest-break-thru-item.rs:35:17 | LL | / if true { LL | | Err(1) @@ -48,7 +48,7 @@ LL | | } found enum `Result<_, {integer}>` error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:49:17 + --> $DIR/dont-suggest-break-thru-item.rs:47:17 | LL | / if true { LL | | Err(1) diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.rs b/tests/ui/lowering/expr-in-pat-issue-99380.rs new file mode 100644 index 0000000000000..1d4a047f717f7 --- /dev/null +++ b/tests/ui/lowering/expr-in-pat-issue-99380.rs @@ -0,0 +1,11 @@ +macro_rules! foo { + ($p:expr) => { + if let $p = Some(42) { + return; + } + }; +} + +fn main() { + foo!(Some(3)); //~ ERROR arbitrary expressions aren't allowed in patterns +} diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.stderr b/tests/ui/lowering/expr-in-pat-issue-99380.stderr new file mode 100644 index 0000000000000..29438c9b06360 --- /dev/null +++ b/tests/ui/lowering/expr-in-pat-issue-99380.stderr @@ -0,0 +1,10 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/expr-in-pat-issue-99380.rs:10:10 + | +LL | foo!(Some(3)); + | ^^^^^^^ + | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression + +error: aborting due to 1 previous error + diff --git a/tests/ui/lto/issue-105637.rs b/tests/ui/lto/issue-105637.rs index 2cc70964b4cbf..884cd5d5e0e17 100644 --- a/tests/ui/lto/issue-105637.rs +++ b/tests/ui/lto/issue-105637.rs @@ -3,8 +3,8 @@ // // That manifested as both `rustc_driver` and rustc's "main" (`compiler/rustc`) having their own // `std::panicking::HOOK` static, and the hook in rustc's main (the default stdlib's) being executed -// when rustc ICEs, instead of the overriden hook from `rustc_driver` (which also displays the query -// stack and information on how to open a GH issue for the encountered ICE). +// when rustc ICEs, instead of the overridden hook from `rustc_driver` (which also displays the +// query stack and information on how to open a GH issue for the encountered ICE). // // In this test, we reproduce this setup by installing a panic hook in both the main and an LTOed // dylib: the last hook set should be the one being executed, the dylib's. diff --git a/tests/ui/macros/issue-118048.stderr b/tests/ui/macros/issue-118048.stderr index 6acf78f63b2bd..4dc5ef71fec69 100644 --- a/tests/ui/macros/issue-118048.stderr +++ b/tests/ui/macros/issue-118048.stderr @@ -12,7 +12,7 @@ help: use type parameters instead LL ~ fn foo(_: $ty, _: $ty) {} LL | } LL | } -LL | +LL | LL ~ foo!(T); | diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr index 447f5dcf8644f..1a446b8c3edbc 100644 --- a/tests/ui/macros/vec-macro-in-pattern.stderr +++ b/tests/ui/macros/vec-macro-in-pattern.stderr @@ -4,6 +4,7 @@ error: arbitrary expressions aren't allowed in patterns LL | Some(vec![43]) => {} | ^^^^^^^^ | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/match/expr_before_ident_pat.stderr b/tests/ui/match/expr_before_ident_pat.stderr index 57a2d2b26cff0..1657c51545cb2 100644 --- a/tests/ui/match/expr_before_ident_pat.stderr +++ b/tests/ui/match/expr_before_ident_pat.stderr @@ -9,6 +9,8 @@ error: arbitrary expressions aren't allowed in patterns | LL | funny!(a, a); | ^ + | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression error: aborting due to 2 previous errors diff --git a/tests/ui/methods/fulfillment-disqualifies-method.rs b/tests/ui/methods/fulfillment-disqualifies-method.rs new file mode 100644 index 0000000000000..639e1c7fc5c02 --- /dev/null +++ b/tests/ui/methods/fulfillment-disqualifies-method.rs @@ -0,0 +1,32 @@ +// Tests that using fulfillment in the trait solver means that we detect that a +// method is impossible, leading to no ambiguity. +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#[derive(Default)] +struct W(A, B); + +trait Constrain { + type Output; +} + +impl Constrain for i32 { + type Output = u32; +} + +trait Impossible {} + +impl W where A: Constrain, B: Impossible { + fn method(&self) {} +} + +impl W { + fn method(&self) {} +} + +fn main() { + let w: W = W::default(); + w.method(); +} diff --git a/tests/ui/methods/leak-check-disquality.rs b/tests/ui/methods/leak-check-disquality.rs new file mode 100644 index 0000000000000..d3b7dd4b80719 --- /dev/null +++ b/tests/ui/methods/leak-check-disquality.rs @@ -0,0 +1,26 @@ +// Tests that using fulfillment in the trait solver means that we detect that a +// method is impossible, leading to no ambiguity. +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +struct W(Option, Option); + +impl<'a> W { + fn method(&self) {} +} + +trait Leak {} +impl Leak for T {} + +impl W { + fn method(&self) {} +} + +fn test<'a>() { + let x: W = W(None, None); + x.method(); +} + +fn main() {} diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index 7d9b38fb29b5f..5a76449e9f95b 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -55,7 +55,7 @@ LL | / y.zero() LL | | .take() | | -^^^^ `Foo` is not an iterator | |______| - | + | | = note: the following trait bounds were not satisfied: `Foo: Iterator` diff --git a/tests/ui/methods/self-type-is-sup-no-eq.rs b/tests/ui/methods/self-type-is-sup-no-eq.rs new file mode 100644 index 0000000000000..ec28b964a0518 --- /dev/null +++ b/tests/ui/methods/self-type-is-sup-no-eq.rs @@ -0,0 +1,24 @@ +//@ check-pass + +// Test that we use `sup` not `eq` during method probe, since this has an effect +// on the leak check. This is (conceptually) minimized from a crater run for +// `wrend 0.3.6`. + +use std::ops::Deref; + +struct A; + +impl Deref for A { + type Target = B; + + fn deref(&self) -> &::Target { todo!() } +} + +struct B(T); +impl B { + fn method(&self) {} +} + +fn main() { + A.method(); +} diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr index 838eaffb5a0dc..162d7ac031a67 100644 --- a/tests/ui/mir/issue-102389.stderr +++ b/tests/ui/mir/issue-102389.stderr @@ -8,7 +8,10 @@ note: if `Enum` implemented `Clone`, you could clone the value --> $DIR/issue-102389.rs:1:1 | LL | enum Enum { A, B, C } - | ^^^^^^^^^ + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | array[*inbounds as usize] + | --------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index f73bff51e7ad1..3bfdd4da6dac8 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -6,8 +6,6 @@ LL | this.is_subset(other) | = note: the following trait bounds were not satisfied: `T: Eq` - `T: PartialEq` - which is required by `T: Eq` `T: Hash` help: consider restricting the type parameters to satisfy the trait bounds | diff --git a/tests/ui/moves/borrow-closures-instead-of-move.rs b/tests/ui/moves/borrow-closures-instead-of-move.rs index 51771ced7f22f..e4bca54e995fa 100644 --- a/tests/ui/moves/borrow-closures-instead-of-move.rs +++ b/tests/ui/moves/borrow-closures-instead-of-move.rs @@ -1,4 +1,4 @@ -fn takes_fn(f: impl Fn()) { +fn takes_fn(f: impl Fn()) { //~ HELP if `impl Fn()` implemented `Clone` loop { takes_fnonce(f); //~^ ERROR use of moved value @@ -6,7 +6,7 @@ fn takes_fn(f: impl Fn()) { } } -fn takes_fn_mut(m: impl FnMut()) { +fn takes_fn_mut(m: impl FnMut()) { //~ HELP if `impl FnMut()` implemented `Clone` if maybe() { takes_fnonce(m); //~^ HELP consider mutably borrowing diff --git a/tests/ui/moves/borrow-closures-instead-of-move.stderr b/tests/ui/moves/borrow-closures-instead-of-move.stderr index 9a84ddef7e64e..ab6ff417efb60 100644 --- a/tests/ui/moves/borrow-closures-instead-of-move.stderr +++ b/tests/ui/moves/borrow-closures-instead-of-move.stderr @@ -15,6 +15,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {} | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function +help: if `impl Fn()` implemented `Clone`, you could clone the value + --> $DIR/borrow-closures-instead-of-move.rs:1:16 + | +LL | fn takes_fn(f: impl Fn()) { + | ^^^^^^^^^ consider constraining this type parameter with `Clone` +LL | loop { +LL | takes_fnonce(f); + | - you could clone this value help: consider borrowing `f` | LL | takes_fnonce(&f); @@ -39,6 +47,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {} | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function +help: if `impl FnMut()` implemented `Clone`, you could clone the value + --> $DIR/borrow-closures-instead-of-move.rs:9:20 + | +LL | fn takes_fn_mut(m: impl FnMut()) { + | ^^^^^^^^^^^^ consider constraining this type parameter with `Clone` +LL | if maybe() { +LL | takes_fnonce(m); + | - you could clone this value help: consider mutably borrowing `m` | LL | takes_fnonce(&mut m); diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs index 86f389cb3af1e..8f2e01bdf1aba 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.rs +++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs @@ -7,6 +7,10 @@ struct NonCopy; //~| NOTE if `NonCopy` implemented `Clone` //~| NOTE if `NonCopy` implemented `Clone` //~| NOTE if `NonCopy` implemented `Clone` +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type fn good() { loop { @@ -21,6 +25,7 @@ fn moved_here_1() { //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait let _used = value; //~^ NOTE value moved here + //~| NOTE you could clone this value let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value used here after move } @@ -32,6 +37,7 @@ fn moved_here_2() { loop { //~ NOTE inside of this loop let _used = value; //~^ NOTE value moved here + //~| NOTE you could clone this value loop { let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value used here after move @@ -45,6 +51,7 @@ fn moved_loop_1() { loop { //~ NOTE inside of this loop let _used = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop + //~| NOTE you could clone this value } } @@ -56,6 +63,7 @@ fn moved_loop_2() { loop { //~ NOTE inside of this loop let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop + //~| NOTE you could clone this value } } diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr index a613f35a35e0a..3a93769ac4549 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr +++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:24:22 + --> $DIR/issue-72649-uninit-in-loop.rs:29:22 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait LL | LL | let _used = value; | ----- value moved here -LL | +... LL | let _used2 = value; | ^^^^^ value used here after move | @@ -14,10 +14,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:36:26 + --> $DIR/issue-72649-uninit-in-loop.rs:42:26 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -34,10 +37,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:46:21 + --> $DIR/issue-72649-uninit-in-loop.rs:52:21 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -51,10 +57,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:57:22 + --> $DIR/issue-72649-uninit-in-loop.rs:64:22 | LL | let mut value = NonCopy{}; | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -68,10 +77,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used2 = value; + | ----- you could clone this value error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:65:21 + --> $DIR/issue-72649-uninit-in-loop.rs:73:21 | LL | let value: NonCopy; | ----- binding declared here but left uninitialized @@ -84,7 +96,7 @@ LL | let value: NonCopy = /* value */; | +++++++++++++ error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:73:21 + --> $DIR/issue-72649-uninit-in-loop.rs:81:21 | LL | let mut value: NonCopy; | --------- binding declared here but left uninitialized diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr index b6ad906bbdb09..815e91b0f4df2 100644 --- a/tests/ui/moves/issue-75904-move-closure-loop.stderr +++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr @@ -15,7 +15,10 @@ note: if `NotCopy` implemented `Clone`, you could clone the value --> $DIR/issue-75904-move-closure-loop.rs:5:1 | LL | struct NotCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | a; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr index e6bf52276ac2f..f2c6008d27eac 100644 --- a/tests/ui/moves/move-fn-self-receiver.stderr +++ b/tests/ui/moves/move-fn-self-receiver.stderr @@ -106,7 +106,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-fn-self-receiver.rs:5:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let ret = mut_foo.use_mut_self(); + | ------- you could clone this value error[E0382]: use of moved value: `rc_foo` --> $DIR/move-fn-self-receiver.rs:55:5 @@ -142,7 +145,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-fn-self-receiver.rs:5:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_add + Foo; + | ------- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr index 9e4a08e0cef54..8a030f0219207 100644 --- a/tests/ui/moves/move-out-of-array-1.stderr +++ b/tests/ui/moves/move-out-of-array-1.stderr @@ -11,7 +11,10 @@ note: if `D` implemented `Clone`, you could clone the value --> $DIR/move-out-of-array-1.rs:5:1 | LL | struct D { _x: u8 } - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | a[i] + | ---- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr index 4759b45892cc4..a8473bb81983d 100644 --- a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr +++ b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -17,6 +17,13 @@ LL | let mut r = R {c: Box::new(f)}; LL | f(&mut r, false) | ^ value borrowed here after move | +help: if `F` implemented `Clone`, you could clone the value + --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:30:16 + | +LL | fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { + | ^ consider constraining this type parameter with `Clone` +LL | let mut r = R {c: Box::new(f)}; + | - you could clone this value help: consider mutably borrowing `f` | LL | let mut r = R {c: Box::new(&mut f)}; diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed index e726c8145c3ba..bfb855c7fb1f4 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -3,6 +3,7 @@ fn duplicate_t(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value (t, t) //~ use of moved value: `t` } @@ -72,10 +73,11 @@ where #[rustfmt::skip] fn existing_colon(t: T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value [t, t]; //~ use of moved value: `t` } -fn existing_colon_in_where(t: T) +fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value where T:, T: Copy //~^ HELP consider further restricting type parameter `T` diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs index ee08ce0fa5ba4..fbe5a1d74c372 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -3,6 +3,7 @@ fn duplicate_t(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value (t, t) //~ use of moved value: `t` } @@ -72,10 +73,11 @@ where #[rustfmt::skip] fn existing_colon(t: T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value [t, t]; //~ use of moved value: `t` } -fn existing_colon_in_where(t: T) +fn existing_colon_in_where(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value where T:, //~^ HELP consider further restricting type parameter `T` diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr index 3e37fcb2141fc..c03204c7b9f10 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -1,21 +1,29 @@ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:7:9 | LL | fn duplicate_t(t: T) -> (T, T) { | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -LL | +... LL | (t, t) | - ^ value used here after move | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:4:16 + | +LL | fn duplicate_t(t: T) -> (T, T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | (t, t) + | - you could clone this value help: consider restricting type parameter `T` | LL | fn duplicate_t(t: T) -> (T, T) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:12:9 | LL | fn duplicate_opt(t: Option) -> (Option, Option) { | - move occurs because `t` has type `Option`, which does not implement the `Copy` trait @@ -31,7 +39,7 @@ LL | fn duplicate_opt(t: Option) -> (Option, Option) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:17:9 | LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { | - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait @@ -47,7 +55,7 @@ LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:22:9 | LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { | - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait @@ -63,7 +71,7 @@ LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { | ++++++ ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:27:9 | LL | fn duplicate_custom(t: S) -> (S, S) { | - move occurs because `t` has type `S`, which does not implement the `Copy` trait @@ -79,7 +87,7 @@ LL | fn duplicate_custom(t: S) -> (S, S) { | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:45:9 | LL | fn duplicate_custom_1(t: S) -> (S, S) where { | - move occurs because `t` has type `S`, which does not implement the `Copy` trait @@ -95,7 +103,7 @@ LL | fn duplicate_custom_1(t: S) -> (S, S) where { | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:53:9 | LL | fn duplicate_custom_2(t: S) -> (S, S) | - move occurs because `t` has type `S`, which does not implement the `Copy` trait @@ -111,7 +119,7 @@ LL | T: A + Copy + Trait, | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:62:9 | LL | fn duplicate_custom_3(t: S) -> (S, S) | - move occurs because `t` has type `S`, which does not implement the `Copy` trait @@ -127,7 +135,7 @@ LL | T: A + Copy + Trait, | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:70:9 | LL | fn duplicate_custom_4(t: S) -> (S, S) | - move occurs because `t` has type `S`, which does not implement the `Copy` trait @@ -143,23 +151,31 @@ LL | fn duplicate_custom_4(t: S) -> (S, S) | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:77:9 | LL | fn existing_colon(t: T) { | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -LL | +... LL | [t, t]; | - ^ value used here after move | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:74:19 + | +LL | fn existing_colon(t: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | [t, t]; + | - you could clone this value help: consider restricting type parameter `T` | LL | fn existing_colon(t: T) { | ++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:85:9 | LL | fn existing_colon_in_where(t: T) | - move occurs because `t` has type `T`, which does not implement the `Copy` trait @@ -169,6 +185,14 @@ LL | [t, t]; | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:80:28 + | +LL | fn existing_colon_in_where(t: T) + | ^ consider constraining this type parameter with `Clone` +... +LL | [t, t]; + | - you could clone this value help: consider further restricting type parameter `T` | LL | T:, T: Copy diff --git a/tests/ui/mut/mut-pattern-internal-mutability.stderr b/tests/ui/mut/mut-pattern-internal-mutability.stderr index 5f2074edb1240..ab80af17a085f 100644 --- a/tests/ui/mut/mut-pattern-internal-mutability.stderr +++ b/tests/ui/mut/mut-pattern-internal-mutability.stderr @@ -2,12 +2,18 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/mut-pattern-internal-mutability.rs:5:5 | LL | let &mut x = foo; - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let &mut mut x = foo; + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let &mut ref mut x = foo; + | ~~~~~~~~~ error[E0506]: cannot assign to `*foo` because it is borrowed --> $DIR/mut-pattern-internal-mutability.rs:13:5 diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs new file mode 100644 index 0000000000000..0ae498c134f09 --- /dev/null +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs @@ -0,0 +1,141 @@ +//@ check-pass +use std::{marker, mem, ptr}; + +fn main() {} + +fn _zero() { + if false { + unsafe { mem::zeroed() } + //~^ warn: never type fallback affects this call to an `unsafe` function + } else { + return; + }; + + // no ; -> type is inferred without fallback + if true { unsafe { mem::zeroed() } } else { return } +} + +fn _trans() { + if false { + unsafe { + struct Zst; + core::mem::transmute(Zst) + //~^ warn: never type fallback affects this call to an `unsafe` function + } + } else { + return; + }; +} + +fn _union() { + if false { + union Union { + a: (), + b: T, + } + + unsafe { Union { a: () }.b } + //~^ warn: never type fallback affects this union access + } else { + return; + }; +} + +fn _deref() { + if false { + unsafe { *ptr::from_ref(&()).cast() } + //~^ warn: never type fallback affects this raw pointer dereference + } else { + return; + }; +} + +fn _only_generics() { + if false { + unsafe fn internally_create(_: Option) { + let _ = mem::zeroed::(); + } + + // We need the option (and unwrap later) to call a function in a way, + // which makes it affected by the fallback, but without having it return anything + let x = None; + + unsafe { internally_create(x) } + //~^ warn: never type fallback affects this call to an `unsafe` function + + x.unwrap() + } else { + return; + }; +} + +fn _stored_function() { + if false { + let zeroed = mem::zeroed; + //~^ warn: never type fallback affects this `unsafe` function + + unsafe { zeroed() } + //~^ warn: never type fallback affects this call to an `unsafe` function + } else { + return; + }; +} + +fn _only_generics_stored_function() { + if false { + unsafe fn internally_create(_: Option) { + let _ = mem::zeroed::(); + } + + let x = None; + let f = internally_create; + //~^ warn: never type fallback affects this `unsafe` function + + unsafe { f(x) } + + x.unwrap() + } else { + return; + }; +} + +fn _method() { + struct S(marker::PhantomData); + + impl S { + #[allow(unused)] // FIXME: the unused lint is probably incorrect here + unsafe fn create_out_of_thin_air(&self) -> T { + todo!() + } + } + + if false { + unsafe { + S(marker::PhantomData).create_out_of_thin_air() + //~^ warn: never type fallback affects this call to an `unsafe` method + } + } else { + return; + }; +} + +// Minimization of the famous `objc` crate issue +fn _objc() { + pub unsafe fn send_message() -> Result { + Ok(unsafe { core::mem::zeroed() }) + } + + macro_rules! msg_send { + () => { + match send_message::<_ /* ?0 */>() { + //~^ warn: never type fallback affects this call to an `unsafe` function + Ok(x) => x, + Err(_) => loop {}, + } + }; + } + + unsafe { + msg_send!(); + } +} diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr new file mode 100644 index 0000000000000..84c9385fd139c --- /dev/null +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr @@ -0,0 +1,87 @@ +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:8:18 + | +LL | unsafe { mem::zeroed() } + | ^^^^^^^^^^^^^ + | + = help: specify the type explicitly + = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default + +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:22:13 + | +LL | core::mem::transmute(Zst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this union access + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:37:18 + | +LL | unsafe { Union { a: () }.b } + | ^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this raw pointer dereference + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:46:18 + | +LL | unsafe { *ptr::from_ref(&()).cast() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:63:18 + | +LL | unsafe { internally_create(x) } + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:77:18 + | +LL | unsafe { zeroed() } + | ^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:74:22 + | +LL | let zeroed = mem::zeroed; + | ^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:91:17 + | +LL | let f = internally_create; + | ^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this call to an `unsafe` method + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:114:13 + | +LL | S(marker::PhantomData).create_out_of_thin_air() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: specify the type explicitly + +warning: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:130:19 + | +LL | match send_message::<_ /* ?0 */>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | msg_send!(); + | ----------- in this macro invocation + | + = help: specify the type explicitly + = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 10 warnings emitted + diff --git a/tests/ui/nll/closure-borrow-spans.stderr b/tests/ui/nll/closure-borrow-spans.stderr index cac22c2ecda49..c466cad25d2e5 100644 --- a/tests/ui/nll/closure-borrow-spans.stderr +++ b/tests/ui/nll/closure-borrow-spans.stderr @@ -25,6 +25,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:19:16 | +LL | let x = 1; + | - binding `x` declared here LL | f = || x; | -- ^ borrowed value does not live long enough | | @@ -85,6 +87,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:52:16 | +LL | let mut x = 1; + | ----- binding `x` declared here LL | f = || x = 0; | -- ^ borrowed value does not live long enough | | @@ -145,6 +149,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:86:16 | +LL | let x = &mut z; + | - binding `x` declared here LL | f = || *x = 0; | -- ^^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr index aa73e91cc77e5..8e47ab780f210 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -37,6 +37,9 @@ LL | fn test() { error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-nested.rs:21:40 | +LL | let y = 22; + | - binding `y` declared here +LL | LL | let mut closure = || { | -- value captured here LL | let mut closure1 = || p = &y; diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr index 949dcc78703a7..c428150aa2f4c 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -23,6 +23,8 @@ LL | fn test() { error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-ref.rs:23:35 | +LL | let y = 22; + | - binding `y` declared here LL | let mut closure = || p = &y; | -- ^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 81b5f09b04157..15f48d88c379b 100644 --- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -1,6 +1,8 @@ error[E0597]: `local_arr` does not live long enough --> $DIR/propagate-multiple-requirements.rs:15:14 | +LL | let local_arr = other_local_arr; + | --------- binding `local_arr` declared here LL | let mut out: &mut &'static [i32] = &mut (&[1] as _); | ------------------- type annotation requires that `local_arr` is borrowed for `'static` LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| { diff --git a/tests/ui/nll/coroutine-distinct-lifetime.rs b/tests/ui/nll/coroutine-distinct-lifetime.rs index ff94a3d54b76b..471fad686c4c3 100644 --- a/tests/ui/nll/coroutine-distinct-lifetime.rs +++ b/tests/ui/nll/coroutine-distinct-lifetime.rs @@ -9,6 +9,7 @@ //@ check-pass fn foo(x: &mut u32) { + #[coroutine] move || { let s = &mut *x; yield; diff --git a/tests/ui/nll/coroutine-upvar-mutability.rs b/tests/ui/nll/coroutine-upvar-mutability.rs index 12853b16b9b75..a7d14173fb9fc 100644 --- a/tests/ui/nll/coroutine-upvar-mutability.rs +++ b/tests/ui/nll/coroutine-upvar-mutability.rs @@ -4,6 +4,8 @@ fn mutate_upvar() { let x = 0; + + #[coroutine] move || { x = 1; //~^ ERROR diff --git a/tests/ui/nll/coroutine-upvar-mutability.stderr b/tests/ui/nll/coroutine-upvar-mutability.stderr index 8922eae315188..8b9be877c8f39 100644 --- a/tests/ui/nll/coroutine-upvar-mutability.stderr +++ b/tests/ui/nll/coroutine-upvar-mutability.stderr @@ -1,9 +1,9 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/coroutine-upvar-mutability.rs:8:9 + --> $DIR/coroutine-upvar-mutability.rs:10:9 | LL | let x = 0; | - help: consider changing this to be mutable: `mut x` -LL | move || { +... LL | x = 1; | ^^^^^ cannot assign diff --git a/tests/ui/nll/extra-unused-mut.rs b/tests/ui/nll/extra-unused-mut.rs index 786ba98508fb6..b040dcc6e5db9 100644 --- a/tests/ui/nll/extra-unused-mut.rs +++ b/tests/ui/nll/extra-unused-mut.rs @@ -18,6 +18,8 @@ fn mutable_upvar() { // #50897 fn coroutine_mutable_upvar() { let mut x = 0; + + #[coroutine] move || { x = 1; yield; @@ -36,13 +38,13 @@ struct Expr { // #51904 fn parse_dot_or_call_expr_with(mut attrs: Vec) { let x = Expr { attrs: vec![] }; - Some(Some(x)).map(|expr| + Some(Some(x)).map(|expr| { expr.map(|mut expr| { attrs.push(666); expr.attrs = attrs; expr }) - ); + }); } // Found when trying to bootstrap rustc diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr index 2aff375f0a77c..496a298a36ce9 100644 --- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr @@ -32,7 +32,10 @@ note: if `S>` implemented `Clone`, you could clone the value --> $DIR/issue-21232-partial-init-and-use.rs:15:1 | LL | struct S { - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut s: S = S::new(); drop(s); + | - you could clone this value error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:116:5 @@ -83,7 +86,10 @@ note: if `S>` implemented `Clone`, you could clone the value --> $DIR/issue-21232-partial-init-and-use.rs:15:1 | LL | struct S { - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut s: S = S::new(); drop(s); + | - you could clone this value error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:142:5 diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed new file mode 100644 index 0000000000000..7692be7ccc801 --- /dev/null +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed @@ -0,0 +1,23 @@ +// Issue 27282: Example 1: This sidesteps the AST checks disallowing +// mutable borrows in match guards by hiding the mutable borrow in a +// guard behind a move (of the ref mut pattern id) within a closure. +//@ run-rustfix +#![feature(if_let_guard)] + +fn main() { + match Some(&4) { + None => {}, + ref mut foo + if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {}, + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo + if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {}, + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + Some(s) => std::process::exit(*s), + } +} diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs index 833ca8afd618e..f3d0a184e03c5 100644 --- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs @@ -1,14 +1,14 @@ // Issue 27282: Example 1: This sidesteps the AST checks disallowing // mutable borrows in match guards by hiding the mutable borrow in a // guard behind a move (of the ref mut pattern id) within a closure. - +//@ run-rustfix #![feature(if_let_guard)] fn main() { match Some(&4) { None => {}, ref mut foo - if { (|| { let bar = foo; bar.take() })(); false } => {}, + if { (|| { let mut bar = foo; bar.take() })(); false } => {}, //~^ ERROR cannot move out of `foo` in pattern guard [E0507] Some(s) => std::process::exit(*s), } @@ -16,7 +16,7 @@ fn main() { match Some(&4) { None => {}, ref mut foo - if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {}, + if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {}, //~^ ERROR cannot move out of `foo` in pattern guard [E0507] Some(s) => std::process::exit(*s), } diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr index 4a512560c8751..7781e77894b89 100644 --- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr @@ -1,22 +1,30 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19 | -LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {}, + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {}, + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34 | -LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {}, - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {}, + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {}, + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.stderr b/tests/ui/nll/issue-27282-mutation-in-guard.stderr index 0b5d723172c76..f73e4aaa489aa 100644 --- a/tests/ui/nll/issue-27282-mutation-in-guard.stderr +++ b/tests/ui/nll/issue-27282-mutation-in-guard.stderr @@ -7,6 +7,10 @@ LL | (|| { let bar = foo; bar.take() })(); | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let bar = foo.clone(); bar.take() })(); + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-mutation-in-guard.rs:20:18 @@ -17,6 +21,10 @@ LL | (|| { let bar = foo; bar.take() })(); | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let bar = foo.clone(); bar.take() })(); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr index f7a525ee9b046..e3f44467550cd 100644 --- a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr +++ b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr @@ -11,6 +11,8 @@ LL | || doit(data); error[E0597]: `data` does not live long enough --> $DIR/issue-42574-diagnostic-in-nested-closure.rs:6:13 | +LL | fn doit(data: &'static mut ()) { + | ---- binding `data` declared here LL | || doit(data); | -- -----^^^^- | | | | diff --git a/tests/ui/nll/issue-48623-coroutine.rs b/tests/ui/nll/issue-48623-coroutine.rs index 3a4a27855d99d..63348a2047c07 100644 --- a/tests/ui/nll/issue-48623-coroutine.rs +++ b/tests/ui/nll/issue-48623-coroutine.rs @@ -12,7 +12,7 @@ impl Drop for WithDrop { fn reborrow_from_coroutine(r: &mut ()) { let d = WithDrop; - move || { d; yield; &mut *r }; //~ WARN unused coroutine that must be used + #[coroutine] move || { d; yield; &mut *r }; //~ WARN unused coroutine that must be used } fn main() {} diff --git a/tests/ui/nll/issue-48623-coroutine.stderr b/tests/ui/nll/issue-48623-coroutine.stderr index 1b7b1735aacb1..4e4cd28ef2ae9 100644 --- a/tests/ui/nll/issue-48623-coroutine.stderr +++ b/tests/ui/nll/issue-48623-coroutine.stderr @@ -1,8 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-48623-coroutine.rs:15:5 + --> $DIR/issue-48623-coroutine.rs:15:18 | -LL | move || { d; yield; &mut *r }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[coroutine] move || { d; yield; &mut *r }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: coroutines are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/tests/ui/nll/issue-55850.rs b/tests/ui/nll/issue-55850.rs index fc873af94638b..bf1e2e7caef6d 100644 --- a/tests/ui/nll/issue-55850.rs +++ b/tests/ui/nll/issue-55850.rs @@ -23,7 +23,7 @@ where } fn bug<'a>() -> impl Iterator { - GenIter(move || { + GenIter(#[coroutine] move || { let mut s = String::new(); yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515] //~| ERROR borrow may still be in use when coroutine yields diff --git a/tests/ui/nll/issue-57362-2.rs b/tests/ui/nll/issue-57362-2.rs index a0b0ea1d03893..664cdf89a3886 100644 --- a/tests/ui/nll/issue-57362-2.rs +++ b/tests/ui/nll/issue-57362-2.rs @@ -18,8 +18,10 @@ impl<'a> X for fn(&'a ()) { } } +// FIXME(@compiler-errors): This error message is less than helpful. fn g() { - let x = ::make_g(); //~ ERROR the function + let x = ::make_g(); + //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn main() {} diff --git a/tests/ui/nll/issue-57362-2.stderr b/tests/ui/nll/issue-57362-2.stderr index 57477f5341ede..24787b990e312 100644 --- a/tests/ui/nll/issue-57362-2.stderr +++ b/tests/ui/nll/issue-57362-2.stderr @@ -1,11 +1,9 @@ -error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied - --> $DIR/issue-57362-2.rs:22:25 +error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope + --> $DIR/issue-57362-2.rs:23:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds + | ^^^^^^ function or associated item not found in `fn(&())` | - = note: the following trait bounds were not satisfied: - `for<'a> fn(&'a ()): X` = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it --> $DIR/issue-57362-2.rs:8:1 diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs index eba859cde2206..69187cab34227 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs @@ -28,7 +28,8 @@ impl Y for fn(T) { } fn higher_ranked_region_has_lost_its_binder() { - let x = ::make_g(); //~ ERROR the function + let x = ::make_g(); + //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn magical() { diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr index d1e94bc702cae..998d06b77065f 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr @@ -1,11 +1,9 @@ -error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied +error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57642-higher-ranked-subtype.rs:31:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds + | ^^^^^^ function or associated item not found in `fn(&())` | - = note: the following trait bounds were not satisfied: - `for<'a> fn(&'a ()): X` = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it --> $DIR/issue-57642-higher-ranked-subtype.rs:4:1 @@ -14,7 +12,7 @@ LL | trait X { | ^^^^^^^ error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope - --> $DIR/issue-57642-higher-ranked-subtype.rs:35:25 + --> $DIR/issue-57642-higher-ranked-subtype.rs:36:25 | LL | let x = ::make_f(); | ^^^^^^ function or associated item not found in `fn(&())` diff --git a/tests/ui/nll/match-guards-always-borrow.fixed b/tests/ui/nll/match-guards-always-borrow.fixed new file mode 100644 index 0000000000000..56e743bf196a6 --- /dev/null +++ b/tests/ui/nll/match-guards-always-borrow.fixed @@ -0,0 +1,66 @@ +#![feature(if_let_guard)] +#![allow(unused_mut)] +//@ run-rustfix + +// Here is arielb1's basic example from rust-lang/rust#27282 +// that AST borrowck is flummoxed by: + +fn should_reject_destructive_mutate_in_guard() { + match Some(&4) { + None => {}, + ref mut foo if { + (|| { let mut bar = foo.clone(); bar.take() })(); + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + false } => { }, + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo if let Some(()) = { + (|| { let mut bar = foo.clone(); bar.take() })(); + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + None } => { }, + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we mutate in the arm +// body. +fn allow_mutate_in_arm_body() { + match Some(&4) { + None => {}, + ref mut foo if foo.is_some() => { foo.take(); () } + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo if let Some(_) = foo => { foo.take(); () } + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we move into the arm +// body. +fn allow_move_into_arm_body() { + match Some(&4) { + None => {}, + mut foo if foo.is_some() => { foo.unwrap(); () } + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + mut foo if let Some(_) = foo => { foo.unwrap(); () } + Some(s) => std::process::exit(*s), + } +} + +fn main() { + should_reject_destructive_mutate_in_guard(); + allow_mutate_in_arm_body(); + allow_move_into_arm_body(); +} diff --git a/tests/ui/nll/match-guards-always-borrow.rs b/tests/ui/nll/match-guards-always-borrow.rs index ff63cc092734a..927d55c42a6e3 100644 --- a/tests/ui/nll/match-guards-always-borrow.rs +++ b/tests/ui/nll/match-guards-always-borrow.rs @@ -1,4 +1,6 @@ #![feature(if_let_guard)] +#![allow(unused_mut)] +//@ run-rustfix // Here is arielb1's basic example from rust-lang/rust#27282 // that AST borrowck is flummoxed by: @@ -7,7 +9,7 @@ fn should_reject_destructive_mutate_in_guard() { match Some(&4) { None => {}, ref mut foo if { - (|| { let bar = foo; bar.take() })(); + (|| { let mut bar = foo; bar.take() })(); //~^ ERROR cannot move out of `foo` in pattern guard [E0507] false } => { }, Some(s) => std::process::exit(*s), @@ -16,7 +18,7 @@ fn should_reject_destructive_mutate_in_guard() { match Some(&4) { None => {}, ref mut foo if let Some(()) = { - (|| { let bar = foo; bar.take() })(); + (|| { let mut bar = foo; bar.take() })(); //~^ ERROR cannot move out of `foo` in pattern guard [E0507] None } => { }, Some(s) => std::process::exit(*s), diff --git a/tests/ui/nll/match-guards-always-borrow.stderr b/tests/ui/nll/match-guards-always-borrow.stderr index afd853c403ee3..bb0c5bd4c9761 100644 --- a/tests/ui/nll/match-guards-always-borrow.stderr +++ b/tests/ui/nll/match-guards-always-borrow.stderr @@ -1,22 +1,30 @@ error[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/match-guards-always-borrow.rs:10:14 + --> $DIR/match-guards-always-borrow.rs:12:14 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | (|| { let mut bar = foo; bar.take() })(); + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let mut bar = foo.clone(); bar.take() })(); + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/match-guards-always-borrow.rs:19:14 + --> $DIR/match-guards-always-borrow.rs:21:14 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | (|| { let mut bar = foo; bar.take() })(); + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let mut bar = foo.clone(); bar.take() })(); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr index 842ecaf524b47..d138412137959 100644 --- a/tests/ui/nll/move-errors.stderr +++ b/tests/ui/nll/move-errors.stderr @@ -8,7 +8,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = *a; + | -- you could clone this value help: consider removing the dereference here | LL - let b = *a; @@ -28,7 +31,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = a[0]; + | ---- you could clone this value help: consider borrowing here | LL | let b = &a[0]; @@ -44,7 +50,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let s = **r; + | --- you could clone this value help: consider removing the dereference here | LL - let s = **r; @@ -61,7 +70,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let s = *r; + | -- you could clone this value help: consider removing the dereference here | LL - let s = *r; @@ -81,7 +93,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = [A("".to_string())][0]; + | ---------------------- you could clone this value help: consider borrowing here | LL | let a = &[A("".to_string())][0]; @@ -126,7 +141,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | b = *a; + | -- you could clone this value error[E0508]: cannot move out of type `[B; 1]`, a non-copy array --> $DIR/move-errors.rs:74:11 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 5227ca8ec17d8..1d086c658dfcd 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; | --- -^ | | || diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 5227ca8ec17d8..1d086c658dfcd 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; | --- -^ | | || diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index c7c08c948abdb..c42ea0172cf75 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -33,7 +33,9 @@ error[E0597]: `a` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here -... +LL | let a = 22; + | - binding `a` declared here +LL | let b = 44; LL | let _closure = || { | -- value captured here LL | let c = 66; diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index b7861a3bd069f..287337c7d52d3 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -34,7 +34,9 @@ error[E0597]: `b` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here -... +LL | let a = 22; +LL | let b = 44; + | - binding `b` declared here LL | let _closure = || { | -- value captured here LL | let c = 66; diff --git a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs index bda5cef979ec2..8aa0d04e500c7 100644 --- a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs +++ b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs @@ -3,7 +3,6 @@ //@ ignore-emscripten no processes //@ compile-flags: -C debug-assertions #![allow(arithmetic_overflow)] -#![feature(generic_nonzero)] use std::num::NonZero; diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 753ba809e7da1..adfd16c6f2b98 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -34,20 +34,6 @@ LL | offset_of!((u8, dyn Trait), 1); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:44:5 - | -LL | offset_of!(Delta, z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized` -note: required because it appears within the type `Alpha` - --> $DIR/offset-of-dst-field.rs:5:8 - | -LL | struct Alpha { - | ^^^^^ - = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:45:5 | @@ -66,6 +52,20 @@ LL | offset_of!(Delta, z); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:44:5 + | +LL | offset_of!(Delta, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized` +note: required because it appears within the type `Alpha` + --> $DIR/offset-of-dst-field.rs:5:8 + | +LL | struct Alpha { + | ^^^^^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:50:5 | diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs index f0c242891d8f9..87918b8ff9539 100644 --- a/tests/ui/offset-of/offset-of-must-use.rs +++ b/tests/ui/offset-of/offset-of-must-use.rs @@ -4,5 +4,5 @@ fn main() { core::mem::offset_of!((String,), 0); - //~^ WARN unused return value of `must_use` that must be used + //~^ WARN unused `offset_of` call that must be used } diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr index b6d88e098d00c..9f0e37a59f43b 100644 --- a/tests/ui/offset-of/offset-of-must-use.stderr +++ b/tests/ui/offset-of/offset-of-must-use.stderr @@ -1,8 +1,8 @@ -warning: unused return value of `must_use` that must be used +warning: unused `offset_of` call that must be used --> $DIR/offset-of-must-use.rs:6:5 | LL | core::mem::offset_of!((String,), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `offset_of` call produces a value | note: the lint level is defined here --> $DIR/offset-of-must-use.rs:3:9 diff --git a/tests/ui/offset-of/offset-of-temporaries.rs b/tests/ui/offset-of/offset-of-temporaries.rs new file mode 100644 index 0000000000000..951a8ee2b5039 --- /dev/null +++ b/tests/ui/offset-of/offset-of-temporaries.rs @@ -0,0 +1,23 @@ +//@ build-pass + +//! Regression test #124478. + +use std::mem::offset_of; + +struct S { + v: u8, + w: u16, +} + +impl S { + fn return_static_slice() -> &'static [usize] { + &[offset_of!(Self, v), offset_of!(Self, w)] + } + fn use_reference() -> usize { + let r = &offset_of!(Self, v); + *r * 6 + } +} + +fn main() { +} diff --git a/tests/ui/packed/packed-struct-drop-aligned.rs b/tests/ui/packed/packed-struct-drop-aligned.rs index 037b8cb78b721..ba3dcb10c61e5 100644 --- a/tests/ui/packed/packed-struct-drop-aligned.rs +++ b/tests/ui/packed/packed-struct-drop-aligned.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(coroutine_trait)] use std::cell::Cell; use std::mem; @@ -7,13 +7,12 @@ use std::ops::Coroutine; use std::pin::Pin; struct Aligned<'a> { - drop_count: &'a Cell + drop_count: &'a Cell, } #[inline(never)] fn check_align(ptr: *const Aligned) { - assert_eq!(ptr as usize % mem::align_of::(), - 0); + assert_eq!(ptr as usize % mem::align_of::(), 0); } impl<'a> Drop for Aligned<'a> { @@ -39,7 +38,8 @@ fn main() { assert_eq!(drop_count.get(), 2); let drop_count = &Cell::new(0); - let mut g = || { + let mut g = #[coroutine] + || { let mut p = Packed(NotCopy(0), Aligned { drop_count }); let _ = &p; p.1 = Aligned { drop_count }; diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.rs b/tests/ui/panic-handler/panic-handler-with-target-feature.rs index 3dfdd2847bf48..8d5ea0703afa5 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.rs +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.rs @@ -9,7 +9,7 @@ use core::panic::PanicInfo; #[panic_handler] #[target_feature(enable = "avx2")] -//~^ ERROR `panic_impl` language item function is not allowed to have `#[target_feature]` +//~^ ERROR `#[panic_handler]` function is not allowed to have `#[target_feature]` fn panic(info: &PanicInfo) -> ! { unimplemented!(); } diff --git a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr index c38feab49c3b1..cb17da3a4efbe 100644 --- a/tests/ui/panic-handler/panic-handler-with-target-feature.stderr +++ b/tests/ui/panic-handler/panic-handler-with-target-feature.stderr @@ -1,11 +1,11 @@ -error: `panic_impl` language item function is not allowed to have `#[target_feature]` +error: `#[panic_handler]` function is not allowed to have `#[target_feature]` --> $DIR/panic-handler-with-target-feature.rs:11:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn panic(info: &PanicInfo) -> ! { - | ------------------------------- `panic_impl` language item function is not allowed to have `#[target_feature]` + | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]` error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.rs b/tests/ui/panic-handler/panic-handler-with-track-caller.rs new file mode 100644 index 0000000000000..09c94139e1697 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.rs @@ -0,0 +1,14 @@ +//@ compile-flags:-C panic=abort +//@ only-x86_64 + +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_handler] +#[track_caller] +//~^ ERROR `#[panic_handler]` function is not allowed to have `#[track_caller]` +fn panic(info: &PanicInfo) -> ! { + unimplemented!(); +} diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr new file mode 100644 index 0000000000000..9ed387fc8d1f4 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr @@ -0,0 +1,11 @@ +error: `#[panic_handler]` function is not allowed to have `#[track_caller]` + --> $DIR/panic-handler-with-track-caller.rs:10:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | fn panic(info: &PanicInfo) -> ! { + | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.rs b/tests/ui/panic-handler/panic-handler-wrong-location.rs index fc3ef401e3db2..49685ee45926e 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.rs +++ b/tests/ui/panic-handler/panic-handler-wrong-location.rs @@ -3,6 +3,6 @@ #![no_std] #![no_main] -#[panic_handler] //~ ERROR `panic_impl` language item must be applied to a function +#[panic_handler] //~ ERROR `panic_impl` lang item must be applied to a function #[no_mangle] static X: u32 = 42; diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.stderr b/tests/ui/panic-handler/panic-handler-wrong-location.stderr index ae3ed5ab12b4c..66ee91aa4c199 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.stderr +++ b/tests/ui/panic-handler/panic-handler-wrong-location.stderr @@ -1,4 +1,4 @@ -error[E0718]: `panic_impl` language item must be applied to a function +error[E0718]: `panic_impl` lang item must be applied to a function --> $DIR/panic-handler-wrong-location.rs:6:1 | LL | #[panic_handler] diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed b/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed new file mode 100644 index 0000000000000..aae71ede77132 --- /dev/null +++ b/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed @@ -0,0 +1,15 @@ +//@ run-rustfix +#![feature(stmt_expr_attributes)] +#![allow(unused_assignments, unused_attributes)] + +fn main() { + let mut x = (#[deprecated] 1) + 2; //~ ERROR ambiguous + + (#[deprecated] x) = 4; //~ ERROR ambiguous + + x = (#[deprecated] 5) as i32; //~ ERROR ambiguous + + let _r = (#[deprecated] 1)..6; //~ ERROR ambiguous + + println!("{}", x); +} diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs b/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs new file mode 100644 index 0000000000000..613e01d743bdd --- /dev/null +++ b/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs @@ -0,0 +1,15 @@ +//@ run-rustfix +#![feature(stmt_expr_attributes)] +#![allow(unused_assignments, unused_attributes)] + +fn main() { + let mut x = #[deprecated] 1 + 2; //~ ERROR ambiguous + + #[deprecated] x = 4; //~ ERROR ambiguous + + x = #[deprecated] 5 as i32; //~ ERROR ambiguous + + let _r = #[deprecated] 1..6; //~ ERROR ambiguous + + println!("{}", x); +} diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr b/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr new file mode 100644 index 0000000000000..0430570fd49d9 --- /dev/null +++ b/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr @@ -0,0 +1,46 @@ +error: ambiguous outer attributes + --> $DIR/attr-binary-expr-ambigous.rs:6:17 + | +LL | let mut x = #[deprecated] 1 + 2; + | ^^^^^^^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | let mut x = (#[deprecated] 1) + 2; + | + + + +error: ambiguous outer attributes + --> $DIR/attr-binary-expr-ambigous.rs:8:5 + | +LL | #[deprecated] x = 4; + | ^^^^^^^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | (#[deprecated] x) = 4; + | + + + +error: ambiguous outer attributes + --> $DIR/attr-binary-expr-ambigous.rs:10:9 + | +LL | x = #[deprecated] 5 as i32; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | x = (#[deprecated] 5) as i32; + | + + + +error: ambiguous outer attributes + --> $DIR/attr-binary-expr-ambigous.rs:12:14 + | +LL | let _r = #[deprecated] 1..6; + | ^^^^^^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | let _r = (#[deprecated] 1)..6; + | + + + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/bad-let-else-statement.rs b/tests/ui/parser/bad-let-else-statement.rs index c3126a493e546..de41a07568fb1 100644 --- a/tests/ui/parser/bad-let-else-statement.rs +++ b/tests/ui/parser/bad-let-else-statement.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![feature(yeet_expr)] #![allow(incomplete_features)] // Necessary for now, while explicit_tail_calls is incomplete #![feature(explicit_tail_calls)] diff --git a/tests/ui/parser/bad-let-else-statement.stderr b/tests/ui/parser/bad-let-else-statement.stderr index 12df8f849abd2..3f7e176b3e31f 100644 --- a/tests/ui/parser/bad-let-else-statement.stderr +++ b/tests/ui/parser/bad-let-else-statement.stderr @@ -1,5 +1,5 @@ error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:10:5 + --> $DIR/bad-let-else-statement.rs:9:5 | LL | } else { | ^ @@ -13,7 +13,7 @@ LL ~ }) else { | error: `for...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:19:7 + --> $DIR/bad-let-else-statement.rs:18:7 | LL | let foo = for i in 1..2 { | --- `else` is attached to this loop @@ -28,7 +28,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:31:5 + --> $DIR/bad-let-else-statement.rs:30:5 | LL | } else { | ^ @@ -43,7 +43,7 @@ LL ~ }) else { | error: `loop...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:40:7 + --> $DIR/bad-let-else-statement.rs:39:7 | LL | let foo = loop { | ---- `else` is attached to this loop @@ -58,7 +58,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:51:5 + --> $DIR/bad-let-else-statement.rs:50:5 | LL | } else { | ^ @@ -73,7 +73,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:62:5 + --> $DIR/bad-let-else-statement.rs:61:5 | LL | } else { | ^ @@ -87,7 +87,7 @@ LL ~ }) else { | error: `while...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:71:7 + --> $DIR/bad-let-else-statement.rs:70:7 | LL | let foo = while false { | ----- `else` is attached to this loop @@ -102,7 +102,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:81:5 + --> $DIR/bad-let-else-statement.rs:80:5 | LL | } else { | ^ @@ -116,7 +116,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:91:5 + --> $DIR/bad-let-else-statement.rs:90:5 | LL | } else { | ^ @@ -130,7 +130,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:102:5 + --> $DIR/bad-let-else-statement.rs:101:5 | LL | } else { | ^ @@ -144,7 +144,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:112:5 + --> $DIR/bad-let-else-statement.rs:111:5 | LL | } else { | ^ @@ -158,7 +158,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:122:5 + --> $DIR/bad-let-else-statement.rs:121:5 | LL | } else { | ^ @@ -172,7 +172,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:132:5 + --> $DIR/bad-let-else-statement.rs:131:5 | LL | } else { | ^ @@ -186,7 +186,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:142:5 + --> $DIR/bad-let-else-statement.rs:141:5 | LL | } else { | ^ @@ -200,7 +200,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:152:5 + --> $DIR/bad-let-else-statement.rs:151:5 | LL | } else { | ^ @@ -214,7 +214,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:162:5 + --> $DIR/bad-let-else-statement.rs:161:5 | LL | } else { | ^ @@ -228,7 +228,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:172:5 + --> $DIR/bad-let-else-statement.rs:171:5 | LL | } else { | ^ @@ -242,7 +242,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:182:31 + --> $DIR/bad-let-else-statement.rs:181:31 | LL | let bad = format_args! {""} else { return; }; | ^ @@ -253,7 +253,7 @@ LL | let bad = format_args! ("") else { return; }; | ~ ~ error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:199:25 + --> $DIR/bad-let-else-statement.rs:198:25 | LL | let x = a! {} else { return; }; | ^ @@ -268,7 +268,7 @@ LL | let x = a! () else { return; }; | ~~ warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:7:5 + --> $DIR/bad-let-else-statement.rs:6:5 | LL | / let foo = { LL | | @@ -281,7 +281,7 @@ LL | | } else { = note: `#[warn(irrefutable_let_patterns)]` on by default warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:26:5 + --> $DIR/bad-let-else-statement.rs:25:5 | LL | / let foo = if true { LL | | @@ -295,7 +295,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:47:5 + --> $DIR/bad-let-else-statement.rs:46:5 | LL | / let foo = match true { LL | | @@ -308,7 +308,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:59:5 + --> $DIR/bad-let-else-statement.rs:58:5 | LL | / let foo = X { LL | | @@ -320,7 +320,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:78:5 + --> $DIR/bad-let-else-statement.rs:77:5 | LL | / let foo = const { LL | | @@ -332,7 +332,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:88:5 + --> $DIR/bad-let-else-statement.rs:87:5 | LL | / let foo = &{ LL | | @@ -344,7 +344,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:99:5 + --> $DIR/bad-let-else-statement.rs:98:5 | LL | / let foo = bar = { LL | | @@ -356,7 +356,7 @@ LL | | } else { = help: consider removing the `else` clause error[E0384]: cannot assign twice to immutable variable `bar` - --> $DIR/bad-let-else-statement.rs:99:15 + --> $DIR/bad-let-else-statement.rs:98:15 | LL | let bar = 0; | --- @@ -371,7 +371,7 @@ LL | | } else { | |_____^ cannot assign twice to immutable variable warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:109:5 + --> $DIR/bad-let-else-statement.rs:108:5 | LL | / let foo = 1 + { LL | | @@ -383,7 +383,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:119:5 + --> $DIR/bad-let-else-statement.rs:118:5 | LL | / let foo = 1..{ LL | | @@ -395,7 +395,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:129:5 + --> $DIR/bad-let-else-statement.rs:128:5 | LL | / let foo = return { LL | | @@ -407,7 +407,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:139:5 + --> $DIR/bad-let-else-statement.rs:138:5 | LL | / let foo = -{ LL | | @@ -419,7 +419,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:149:5 + --> $DIR/bad-let-else-statement.rs:148:5 | LL | / let foo = do yeet { LL | | @@ -431,7 +431,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:159:5 + --> $DIR/bad-let-else-statement.rs:158:5 | LL | / let foo = become { LL | | @@ -443,7 +443,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:169:5 + --> $DIR/bad-let-else-statement.rs:168:5 | LL | / let foo = |x: i32| { LL | | @@ -455,7 +455,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:179:5 + --> $DIR/bad-let-else-statement.rs:178:5 | LL | let ok = format_args!("") else { return; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -464,7 +464,7 @@ LL | let ok = format_args!("") else { return; }; = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:182:5 + --> $DIR/bad-let-else-statement.rs:181:5 | LL | let bad = format_args! {""} else { return; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -473,7 +473,7 @@ LL | let bad = format_args! {""} else { return; }; = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:189:19 + --> $DIR/bad-let-else-statement.rs:188:19 | LL | () => { {} } | ___________________^ @@ -493,7 +493,7 @@ LL | b!(1); b!(2); = note: this warning originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:189:19 + --> $DIR/bad-let-else-statement.rs:188:19 | LL | () => { {} } | ___________________^ diff --git a/tests/ui/parser/expr-rarrow-call.fixed b/tests/ui/parser/expr-rarrow-call.fixed new file mode 100644 index 0000000000000..9a05e20092dd8 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.fixed @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named.foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed.0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t.0; //~ ERROR `->` used for field access or method call + t.1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo.clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.rs b/tests/ui/parser/expr-rarrow-call.rs new file mode 100644 index 0000000000000..760b0f6f345b9 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.rs @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named->foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed->0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t->0; //~ ERROR `->` used for field access or method call + t->1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo->clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr new file mode 100644 index 0000000000000..90082f98cb5f8 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -0,0 +1,42 @@ +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:14:10 + | +LL | named->foo; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:18:12 + | +LL | unnamed->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:22:6 + | +LL | t->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:23:6 + | +LL | t->1; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:30:8 + | +LL | foo->clone(); + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs index e758e5af4d9ec..cf14eebec2b76 100644 --- a/tests/ui/parser/issues/issue-118530-ice.rs +++ b/tests/ui/parser/issues/issue-118530-ice.rs @@ -3,8 +3,9 @@ fn bar() -> String { [1, 2, 3].iter() //~ ERROR expected `;`, found `#` #[feature] attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn` - //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + //~^ ERROR expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` //~| ERROR expected `;`, found `bar` + //~| ERROR `->` used for field access or method call #[attr] [1, 2, 3].iter().map().collect::() #[attr] diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index ef573fb7ba3de..75c6a40c74450 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -33,11 +33,19 @@ LL | attr::fn bar() -> String { | | | help: add `;` here -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->` +error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/issue-118530-ice.rs:5:30 + | +LL | attr::fn bar() -> String { + | ^ expected one of 7 possible tokens -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/parser/issues/issue-32505.stderr b/tests/ui/parser/issues/issue-32505.stderr index 27ad2c3e5be11..0eaa5efd525fc 100644 --- a/tests/ui/parser/issues/issue-32505.stderr +++ b/tests/ui/parser/issues/issue-32505.stderr @@ -9,7 +9,7 @@ LL | foo(|_|) help: you might have meant to open the body of the closure | LL | foo(|_| {}) - | ++ + | ++ error[E0425]: cannot find function `foo` in this scope --> $DIR/issue-32505.rs:2:5 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 00964cb8336ed..e925fe78f3393 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -337,7 +337,10 @@ note: if `U` implemented `Clone`, you could clone the value --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 | LL | struct U; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | - you could clone this value error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 @@ -350,7 +353,10 @@ note: if `U` implemented `Clone`, you could clone the value --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 | LL | struct U; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | - you could clone this value = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0507]: cannot move out of `a` in pattern guard diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr index e25c30cd4926a..41d1b79d97d1c 100644 --- a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr +++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -70,13 +70,19 @@ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/pat-at-same-name-both.rs:13:15 | LL | Ok(a @ b @ a) - | - - | | - | first assignment to `a` - | help: consider making this binding mutable: `mut a` + | - first assignment to `a` LL | LL | | Err(a @ b @ a) | ^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | Ok(a @ b @ mut a) + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | Ok(a @ b @ ref mut a) + | ~~~~~~~~~ error: aborting due to 12 previous errors diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs new file mode 100644 index 0000000000000..5881e4166a46f --- /dev/null +++ b/tests/ui/pattern/deref-patterns/bindings.rs @@ -0,0 +1,64 @@ +//@ run-pass +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn simple_vec(vec: Vec) -> u32 { + match vec { + deref!([]) => 100, + deref!([x]) if x == 4 => x + 4, + deref!([x]) => x, + deref!([1, x]) => x + 200, + deref!(ref slice) => slice.iter().sum(), + _ => 2000, + } +} + +fn nested_vec(vecvec: Vec>) -> u32 { + match vecvec { + deref!([]) => 0, + deref!([deref!([x])]) => x, + deref!([deref!([0, x]) | deref!([1, x])]) => x, + deref!([ref x]) => x.iter().sum(), + deref!([deref!([]), deref!([1, x, y])]) => y - x, + _ => 2000, + } +} + +fn ref_mut(val: u32) -> u32 { + let mut b = Box::new(0u32); + match &mut b { + deref!(_x) if false => unreachable!(), + deref!(x) => { + *x = val; + } + _ => unreachable!(), + } + let deref!(x) = &b else { unreachable!() }; + *x +} + +#[rustfmt::skip] +fn or_and_guard(tuple: (u32, u32)) -> u32 { + let mut sum = 0; + let b = Box::new(tuple); + match b { + deref!((x, _) | (_, x)) if { sum += x; false } => {}, + _ => {}, + } + sum +} + +fn main() { + assert_eq!(simple_vec(vec![1]), 1); + assert_eq!(simple_vec(vec![1, 2]), 202); + assert_eq!(simple_vec(vec![1, 2, 3]), 6); + assert_eq!(simple_vec(vec![4]), 8); + + assert_eq!(nested_vec(vec![vec![0, 42]]), 42); + assert_eq!(nested_vec(vec![vec![1, 42]]), 42); + assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6); + assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1); + + assert_eq!(ref_mut(42), 42); + assert_eq!(or_and_guard((10, 32)), 42); +} diff --git a/tests/ui/pattern/deref-patterns/branch.rs b/tests/ui/pattern/deref-patterns/branch.rs new file mode 100644 index 0000000000000..1bac1006d9dc0 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/branch.rs @@ -0,0 +1,40 @@ +//@ run-pass +// Test the execution of deref patterns. +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn branch(vec: Vec) -> u32 { + match vec { + deref!([]) => 0, + deref!([1, _, 3]) => 1, + deref!([2, ..]) => 2, + _ => 1000, + } +} + +fn nested(vec: Vec>) -> u32 { + match vec { + deref!([deref!([]), ..]) => 1, + deref!([deref!([0, ..]), deref!([1, ..])]) => 2, + _ => 1000, + } +} + +fn main() { + assert!(matches!(Vec::::new(), deref!([]))); + assert!(matches!(vec![1], deref!([1]))); + assert!(matches!(&vec![1], deref!([1]))); + assert!(matches!(vec![&1], deref!([1]))); + assert!(matches!(vec![vec![1]], deref!([deref!([1])]))); + + assert_eq!(branch(vec![]), 0); + assert_eq!(branch(vec![1, 2, 3]), 1); + assert_eq!(branch(vec![3, 2, 1]), 1000); + assert_eq!(branch(vec![2]), 2); + assert_eq!(branch(vec![2, 3]), 2); + assert_eq!(branch(vec![3, 2]), 1000); + + assert_eq!(nested(vec![vec![], vec![2]]), 1); + assert_eq!(nested(vec![vec![0], vec![1]]), 2); + assert_eq!(nested(vec![vec![0, 2], vec![1, 2]]), 2); +} diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs new file mode 100644 index 0000000000000..84b5ec09dc7d8 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs @@ -0,0 +1,24 @@ +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +use std::rc::Rc; + +struct Struct; + +fn cant_move_out_box(b: Box) -> Struct { + match b { + //~^ ERROR: cannot move out of a shared reference + deref!(x) => x, + _ => unreachable!(), + } +} + +fn cant_move_out_rc(rc: Rc) -> Struct { + match rc { + //~^ ERROR: cannot move out of a shared reference + deref!(x) => x, + _ => unreachable!(), + } +} + +fn main() {} diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr new file mode 100644 index 0000000000000..108db6d9e4b53 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/cant_move_out_of_pattern.rs:9:11 + | +LL | match b { + | ^ +LL | +LL | deref!(x) => x, + | - + | | + | data moved here + | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of a shared reference + --> $DIR/cant_move_out_of_pattern.rs:17:11 + | +LL | match rc { + | ^^ +LL | +LL | deref!(x) => x, + | - + | | + | data moved here + | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs new file mode 100644 index 0000000000000..fc0ddedac2b78 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/closure_capture.rs @@ -0,0 +1,21 @@ +//@ run-pass +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn main() { + let b = Box::new("aaa".to_string()); + let f = || { + let deref!(ref s) = b else { unreachable!() }; + assert_eq!(s.len(), 3); + }; + assert_eq!(b.len(), 3); + f(); + + let mut b = Box::new("aaa".to_string()); + let mut f = || { + let deref!(ref mut s) = b else { unreachable!() }; + s.push_str("aa"); + }; + f(); + assert_eq!(b.len(), 5); +} diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.rs b/tests/ui/pattern/deref-patterns/fake_borrows.rs new file mode 100644 index 0000000000000..35fa9cbf7d859 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/fake_borrows.rs @@ -0,0 +1,14 @@ +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +#[rustfmt::skip] +fn main() { + let mut b = Box::new(false); + match b { + deref!(true) => {} + _ if { *b = true; false } => {} + //~^ ERROR cannot assign `*b` in match guard + deref!(false) => {} + _ => {}, + } +} diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.stderr b/tests/ui/pattern/deref-patterns/fake_borrows.stderr new file mode 100644 index 0000000000000..6a591e6416c5d --- /dev/null +++ b/tests/ui/pattern/deref-patterns/fake_borrows.stderr @@ -0,0 +1,12 @@ +error[E0510]: cannot assign `*b` in match guard + --> $DIR/fake_borrows.rs:9:16 + | +LL | match b { + | - value is immutable in match guard +LL | deref!(true) => {} +LL | _ if { *b = true; false } => {} + | ^^^^^^^^^ cannot assign + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0510`. diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs index ead6dcdbaf0f9..f23f7042cd892 100644 --- a/tests/ui/pattern/deref-patterns/typeck.rs +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -4,6 +4,8 @@ use std::rc::Rc; +struct Struct; + fn main() { let vec: Vec = Vec::new(); match vec { @@ -22,10 +24,12 @@ fn main() { deref!(1..) => {} _ => {} } - // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a - // place of type `str`. - // match "foo".to_string() { - // box "foo" => {} - // _ => {} - // } + let _: &Struct = match &Rc::new(Struct) { + deref!(x) => x, + _ => unreachable!(), + }; + let _: &[Struct] = match &Rc::new(vec![Struct]) { + deref!(deref!(x)) => x, + _ => unreachable!(), + }; } diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs new file mode 100644 index 0000000000000..040118449ecca --- /dev/null +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -0,0 +1,17 @@ +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn main() { + // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a + // place of type `str`. + match "foo".to_string() { + deref!("foo") => {} + //~^ ERROR: mismatched types + _ => {} + } + match &"foo".to_string() { + deref!("foo") => {} + //~^ ERROR: mismatched types + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr new file mode 100644 index 0000000000000..1c14802745a0c --- /dev/null +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/typeck_fail.rs:8:16 + | +LL | match "foo".to_string() { + | ----------------- this expression has type `String` +LL | deref!("foo") => {} + | ^^^^^ expected `str`, found `&str` + +error[E0308]: mismatched types + --> $DIR/typeck_fail.rs:13:16 + | +LL | match &"foo".to_string() { + | ------------------ this expression has type `&String` +LL | deref!("foo") => {} + | ^^^^^ expected `str`, found `&str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/issue-92074-macro-ice.stderr b/tests/ui/pattern/issue-92074-macro-ice.stderr index b340afff010f7..025592116e511 100644 --- a/tests/ui/pattern/issue-92074-macro-ice.stderr +++ b/tests/ui/pattern/issue-92074-macro-ice.stderr @@ -7,6 +7,7 @@ LL | () => { force_expr!(Vec::new()) } LL | assert!(matches!(x, En::A(make_vec!()))); | ----------- in this macro invocation | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression = note: this error originates in the macro `make_vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: arbitrary expressions aren't allowed in patterns @@ -18,6 +19,7 @@ LL | () => { force_pat!(get_usize(), get_usize()) } LL | assert!(matches!(5, make_pat!())); | ----------- in this macro invocation | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) error: arbitrary expressions aren't allowed in patterns @@ -29,6 +31,7 @@ LL | () => { force_pat!(get_usize(), get_usize()) } LL | assert!(matches!(5, make_pat!())); | ----------- in this macro invocation | + = note: the `expr` fragment specifier forces the metavariable's content to be an expression = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index a033cc0655ef9..1e7b990b67cf3 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -15,12 +15,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1` --> $DIR/borrowck-move-ref-pattern.rs:9:5 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; - | --- - | | - | first assignment to `_x1` - | help: consider making this binding mutable: `mut _x1` + | --- first assignment to `_x1` LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let [ref _x0_hold, mut _x1, ref xs_hold @ ..] = arr; + | ~~~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let [ref _x0_hold, ref mut _x1, ref xs_hold @ ..] = arr; + | ~~~~~~~~~~~ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:11:10 @@ -73,12 +79,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1` --> $DIR/borrowck-move-ref-pattern.rs:23:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; - | --- - | | - | first assignment to `_x1` - | help: consider making this binding mutable: `mut _x1` + | --- first assignment to `_x1` LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let (ref _x0, mut _x1, ref _x2, ..) = tup; + | ~~~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let (ref _x0, ref mut _x1, ref _x2, ..) = tup; + | ~~~~~~~~~~~ error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable --> $DIR/borrowck-move-ref-pattern.rs:24:20 diff --git a/tests/ui/pattern/mut-ref-mut-2021.stderr b/tests/ui/pattern/mut-ref-mut-2021.stderr index eb31ffa0e30a2..ebf7979edb6ea 100644 --- a/tests/ui/pattern/mut-ref-mut-2021.stderr +++ b/tests/ui/pattern/mut-ref-mut-2021.stderr @@ -2,12 +2,18 @@ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/mut-ref-mut-2021.rs:9:5 | LL | let Foo(a) = Foo(0); - | - - | | - | first assignment to `a` - | help: consider making this binding mutable: `mut a` + | - first assignment to `a` LL | a = 42; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let Foo(mut a) = Foo(0); + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let Foo(ref mut a) = Foo(0); + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/mut-ref-mut-2021.rs:15:5 diff --git a/tests/ui/polymorphization/coroutine.rs b/tests/ui/polymorphization/coroutine.rs index a989947f78738..22ceadfb194d9 100644 --- a/tests/ui/polymorphization/coroutine.rs +++ b/tests/ui/polymorphization/coroutine.rs @@ -32,6 +32,7 @@ where #[rustc_polymorphize_error] pub fn unused_type() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { //~^ ERROR item has unused generic parameters yield 1; @@ -41,6 +42,7 @@ pub fn unused_type() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin #[rustc_polymorphize_error] pub fn used_type_in_yield() -> impl Coroutine<(), Yield = Y, Return = u32> + Unpin { + #[coroutine] || { yield Y::default(); 2 @@ -49,6 +51,7 @@ pub fn used_type_in_yield() -> impl Coroutine<(), Yield = Y, Return #[rustc_polymorphize_error] pub fn used_type_in_return() -> impl Coroutine<(), Yield = u32, Return = R> + Unpin { + #[coroutine] || { yield 3; R::default() @@ -57,6 +60,7 @@ pub fn used_type_in_return() -> impl Coroutine<(), Yield = u32, Retu #[rustc_polymorphize_error] pub fn unused_const() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { //~^ ERROR item has unused generic parameters yield 1; @@ -67,6 +71,7 @@ pub fn unused_const() -> impl Coroutine<(), Yield = u32, Return = #[rustc_polymorphize_error] pub fn used_const_in_yield() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { yield Y; 2 @@ -76,6 +81,7 @@ pub fn used_const_in_yield() -> impl Coroutine<(), Yield = u32, Re #[rustc_polymorphize_error] pub fn used_const_in_return() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { yield 4; R diff --git a/tests/ui/polymorphization/coroutine.stderr b/tests/ui/polymorphization/coroutine.stderr index 67b55a5988317..07e29184226d9 100644 --- a/tests/ui/polymorphization/coroutine.stderr +++ b/tests/ui/polymorphization/coroutine.stderr @@ -8,18 +8,20 @@ LL | #![feature(generic_const_exprs, coroutines, coroutine_trait, rustc_attrs)] = note: `#[warn(incomplete_features)]` on by default error: item has unused generic parameters - --> $DIR/coroutine.rs:35:5 + --> $DIR/coroutine.rs:36:5 | LL | pub fn unused_type() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { | - generic parameter `T` is unused +LL | #[coroutine] LL | || { | ^^ error: item has unused generic parameters - --> $DIR/coroutine.rs:60:5 + --> $DIR/coroutine.rs:64:5 | LL | pub fn unused_const() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { | ------------ generic parameter `T` is unused +LL | #[coroutine] LL | || { | ^^ diff --git a/tests/ui/print_type_sizes/coroutine.rs b/tests/ui/print_type_sizes/coroutine.rs index 61488c51f0530..1533578878944 100644 --- a/tests/ui/print_type_sizes/coroutine.rs +++ b/tests/ui/print_type_sizes/coroutine.rs @@ -7,6 +7,7 @@ use std::ops::Coroutine; fn coroutine(array: [u8; C]) -> impl Coroutine { + #[coroutine] move |()| { yield (); let _ = array; diff --git a/tests/ui/print_type_sizes/coroutine.stdout b/tests/ui/print_type_sizes/coroutine.stdout index 5d51339558caf..339bbddfc2a93 100644 --- a/tests/ui/print_type_sizes/coroutine.stdout +++ b/tests/ui/print_type_sizes/coroutine.stdout @@ -1,4 +1,4 @@ -print-type-size type: `{coroutine@$DIR/coroutine.rs:10:5: 10:14}`: 8193 bytes, alignment: 1 bytes +print-type-size type: `{coroutine@$DIR/coroutine.rs:11:5: 11:14}`: 8193 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 8192 bytes print-type-size upvar `.array`: 8192 bytes diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.rs b/tests/ui/print_type_sizes/coroutine_discr_placement.rs index 4b9f67a79997f..d97b0b28ed0fe 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.rs +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.rs @@ -5,11 +5,12 @@ // Tests a coroutine that has its discriminant as the *final* field. // Avoid emitting panic handlers, like the rest of these tests... -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(dropping_copy_types)] pub fn foo() { - let a = || { + let a = #[coroutine] + || { { let w: i32 = 4; yield; diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout index 71a7f3c63815c..4ce1ce46f6e82 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout @@ -1,4 +1,4 @@ -print-type-size type: `{coroutine@$DIR/coroutine_discr_placement.rs:12:13: 12:15}`: 8 bytes, alignment: 4 bytes +print-type-size type: `{coroutine@$DIR/coroutine_discr_placement.rs:13:5: 13:7}`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 7 bytes diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 07da1cff27a74..5dda0da845825 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -15,7 +15,6 @@ // ^-- needed because `--pass check` does not emit the output needed. // FIXME: consider using an attribute instead of side-effects. #![allow(dead_code)] -#![feature(generic_nonzero)] #![feature(rustc_attrs)] use std::num::NonZero; diff --git a/tests/ui/proc-macro/issue-81555.rs b/tests/ui/proc-macro/issue-81555.rs index 7a61a31952f41..b337ab7ce37db 100644 --- a/tests/ui/proc-macro/issue-81555.rs +++ b/tests/ui/proc-macro/issue-81555.rs @@ -10,6 +10,5 @@ use test_macros::identity_attr; fn main() { let _x; let y = (); - #[identity_attr] - _x = y; + (#[identity_attr] _x) = y; } diff --git a/tests/ui/regions/regions-addr-of-upvar-self.stderr b/tests/ui/regions/regions-addr-of-upvar-self.stderr index c16a6f8585b69..3a028cc9e211c 100644 --- a/tests/ui/regions/regions-addr-of-upvar-self.stderr +++ b/tests/ui/regions/regions-addr-of-upvar-self.stderr @@ -20,6 +20,8 @@ LL | let p: &'static mut usize = &mut self.food; error[E0597]: `self` does not live long enough --> $DIR/regions-addr-of-upvar-self.rs:8:46 | +LL | pub fn chase_cat(&mut self) { + | --------- binding `self` declared here LL | let _f = || { | -- value captured here LL | let p: &'static mut usize = &mut self.food; diff --git a/tests/ui/regions/regions-nested-fns-2.stderr b/tests/ui/regions/regions-nested-fns-2.stderr index 254497639a179..02359fe1213d8 100644 --- a/tests/ui/regions/regions-nested-fns-2.stderr +++ b/tests/ui/regions/regions-nested-fns-2.stderr @@ -1,6 +1,9 @@ error[E0597]: `y` does not live long enough --> $DIR/regions-nested-fns-2.rs:7:25 | +LL | let y = 3; + | - binding `y` declared here +LL | ignore( LL | |z| { | --- value captured here LL | if false { &y } else { z } diff --git a/tests/ui/regions/regions-nested-fns.stderr b/tests/ui/regions/regions-nested-fns.stderr index ee43f9fa5724d..23b3f78dd4eb5 100644 --- a/tests/ui/regions/regions-nested-fns.stderr +++ b/tests/ui/regions/regions-nested-fns.stderr @@ -27,6 +27,9 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/regions-nested-fns.rs:10:15 | +LL | let y = 3; + | - binding `y` declared here +... LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { | --- value captured here LL | ay = x; diff --git a/tests/ui/regions/regions-steal-closure.stderr b/tests/ui/regions/regions-steal-closure.stderr index 9324eb892a67d..50068b32fa3a7 100644 --- a/tests/ui/regions/regions-steal-closure.stderr +++ b/tests/ui/regions/regions-steal-closure.stderr @@ -4,6 +4,7 @@ error[E0597]: `i` does not live long enough LL | let mut cl_box = { | ---------- borrow later stored here LL | let mut i = 3; + | ----- binding `i` declared here LL | box_it(Box::new(|| i += 1)) | -- ^ borrowed value does not live long enough | | diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs index 5d11941414f43..97fc1276f6175 100644 --- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs @@ -4,7 +4,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } -// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs` +// The incorrect case without `for<'a>` is tested for in `rfc1623-3.rs` static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); @@ -26,10 +26,10 @@ static SOME_STRUCT: &SomeStruct = &SomeStruct { foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, - //~^ ERROR implementation of `Fn` is not general enough - //~| ERROR implementation of `Fn` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough + //~^ ERROR implementation of `FnOnce` is not general enough //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `Fn` is not general enough }; // very simple test for a 'static static with default lifetime diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs index d5c8a529e1e37..9fdceefbf9b92 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs @@ -113,7 +113,7 @@ fn dyn_coroutine( } fn test_coroutine() { - let coroutine = #[track_caller] |arg: String| { + let coroutine = #[track_caller] #[coroutine] |arg: String| { yield ("first", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller()); }; @@ -136,7 +136,7 @@ fn test_coroutine() { assert_eq!(mono_loc.line(), mono_line); assert_eq!(mono_loc.column(), 42); - let non_tracked_coroutine = || { yield Location::caller(); }; + let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); }; let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) { CoroutineState::Yielded(val) => val, @@ -144,7 +144,7 @@ fn test_coroutine() { }; assert_eq!(non_tracked_loc.file(), file!()); assert_eq!(non_tracked_loc.line(), non_tracked_line); - assert_eq!(non_tracked_loc.column(), 44); + assert_eq!(non_tracked_loc.column(), 57); } diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index c73b8d7e4d29b..de002ef71d7d3 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -1,4 +1,6 @@ //@ only-x86_64 +// Set the base cpu explicitly, in case the default has been changed. +//@ compile-flags: -C target-cpu=x86-64 #![feature(target_feature_11)] diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index d9d7e297f8e97..aa660db38679c 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:25:5 + --> $DIR/safe-calls.rs:27:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -8,7 +8,7 @@ LL | sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:27:5 + --> $DIR/safe-calls.rs:29:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -16,7 +16,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:31:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -24,7 +24,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:35:5 + --> $DIR/safe-calls.rs:37:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -32,7 +32,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:37:5 + --> $DIR/safe-calls.rs:39:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -40,7 +40,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:43:5 + --> $DIR/safe-calls.rs:45:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -49,7 +49,7 @@ LL | sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:45:5 + --> $DIR/safe-calls.rs:47:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -57,7 +57,7 @@ LL | avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:47:5 + --> $DIR/safe-calls.rs:49:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -65,7 +65,7 @@ LL | Quux.avx_bmi2(); = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:54:5 + --> $DIR/safe-calls.rs:56:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -74,7 +74,7 @@ LL | sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:58:15 + --> $DIR/safe-calls.rs:60:15 | LL | const _: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -83,7 +83,7 @@ LL | const _: () = sse2(); = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:61:15 + --> $DIR/safe-calls.rs:63:15 | LL | const _: () = sse2_and_fxsr(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -92,7 +92,7 @@ LL | const _: () = sse2_and_fxsr(); = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) - --> $DIR/safe-calls.rs:68:5 + --> $DIR/safe-calls.rs:70:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -101,12 +101,12 @@ LL | sse2(); = help: in order for the call to be safe, the context requires the following additional target feature: sse2 = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` note: an unsafe function restricts its caller, but its body is safe by default - --> $DIR/safe-calls.rs:67:1 + --> $DIR/safe-calls.rs:69:1 | LL | unsafe fn needs_unsafe_block() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: the lint level is defined here - --> $DIR/safe-calls.rs:64:8 + --> $DIR/safe-calls.rs:66:8 | LL | #[deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs index 5ff3cd25e67be..402efaf50271a 100644 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs @@ -1,7 +1,5 @@ // Tests that dlltool failing to generate an import library will raise an error. -//@ only-gnu -//@ only-windows //@ needs-dlltool //@ compile-flags: --crate-type lib --emit link //@ normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL" diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs index ac6a2998a4762..bcf6dda7a44dc 100644 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs @@ -1,7 +1,6 @@ // Tests that failing to run dlltool will raise an error. -//@ only-gnu -//@ only-windows +//@ needs-dlltool //@ compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe #[link(name = "foo", kind = "raw-dylib")] extern "C" { diff --git a/tests/ui/rust-2018/async-ident-allowed.stderr b/tests/ui/rust-2018/async-ident-allowed.stderr index b413c0fd9ba8f..378c81d3c770b 100644 --- a/tests/ui/rust-2018/async-ident-allowed.stderr +++ b/tests/ui/rust-2018/async-ident-allowed.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(keyword_idents)]` implied by `#[deny(rust_2018_compatibility)]` + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(rust_2018_compatibility)]` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/async-ident.stderr b/tests/ui/rust-2018/async-ident.stderr index d15250c54ec92..5b8d8184f4f3d 100644 --- a/tests/ui/rust-2018/async-ident.stderr +++ b/tests/ui/rust-2018/async-ident.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:12:7 diff --git a/tests/ui/rust-2018/dyn-keyword.stderr b/tests/ui/rust-2018/dyn-keyword.stderr index 6f9a5ddb14fe1..f8245bc88f573 100644 --- a/tests/ui/rust-2018/dyn-keyword.stderr +++ b/tests/ui/rust-2018/dyn-keyword.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/try-ident.stderr b/tests/ui/rust-2018/try-ident.stderr index 74015ac9da426..eaf4c235697c7 100644 --- a/tests/ui/rust-2018/try-ident.stderr +++ b/tests/ui/rust-2018/try-ident.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]` + = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]` warning: `try` is a keyword in the 2018 edition --> $DIR/try-ident.rs:12:4 diff --git a/tests/ui/rust-2018/try-macro.stderr b/tests/ui/rust-2018/try-macro.stderr index 760378f0955c7..095c755539db4 100644 --- a/tests/ui/rust-2018/try-macro.stderr +++ b/tests/ui/rust-2018/try-macro.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]` + = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]` warning: 1 warning emitted diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr new file mode 100644 index 0000000000000..b12363184b713 --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.e2015.stderr @@ -0,0 +1,26 @@ +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:6:4 + | +LL | fn gen() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 +note: the lint level is defined here + --> $DIR/gen-kw.rs:4:9 + | +LL | #![deny(rust_2024_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]` + +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:12:9 + | +LL | let gen = r#gen; + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr new file mode 100644 index 0000000000000..e10fc4c45120c --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.e2018.stderr @@ -0,0 +1,26 @@ +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:6:4 + | +LL | fn gen() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 +note: the lint level is defined here + --> $DIR/gen-kw.rs:4:9 + | +LL | #![deny(rust_2024_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]` + +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:12:9 + | +LL | let gen = r#gen; + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs new file mode 100644 index 0000000000000..3d2a3f9516558 --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.rs @@ -0,0 +1,16 @@ +//@ revisions: e2015 e2018 +//@[e2018] edition: 2018 + +#![deny(rust_2024_compatibility)] + +fn gen() {} +//~^ ERROR `gen` is a keyword in the 2024 edition +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! +//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + +fn main() { + let gen = r#gen; + //~^ ERROR `gen` is a keyword in the 2024 edition + //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! +} diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs index 5c6a489a7e89e..ad994fcf73700 100644 --- a/tests/ui/sanitizer/cfi-coroutine.rs +++ b/tests/ui/sanitizer/cfi-coroutine.rs @@ -14,7 +14,7 @@ //@ compile-flags: --test -Z unstable-options //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(coroutine_trait)] #![feature(noop_waker)] #![feature(gen_blocks)] @@ -27,7 +27,7 @@ use std::async_iter::AsyncIterator; #[test] fn general_coroutine() { - let mut coro = |x: i32| { + let mut coro = #[coroutine] |x: i32| { yield x; "done" }; diff --git a/tests/ui/self/arbitrary-self-opaque.rs b/tests/ui/self/arbitrary-self-opaque.rs index 99357dde3e149..3331b037b0514 100644 --- a/tests/ui/self/arbitrary-self-opaque.rs +++ b/tests/ui/self/arbitrary-self-opaque.rs @@ -6,7 +6,7 @@ type Bar = impl Sized; impl Foo { fn foo(self: Bar) {} - //~^ ERROR: invalid `self` parameter type: Bar + //~^ ERROR: invalid `self` parameter type: `Bar` } fn main() {} diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr index 6b5db8d849329..0cbe22afac31c 100644 --- a/tests/ui/self/arbitrary-self-opaque.stderr +++ b/tests/ui/self/arbitrary-self-opaque.stderr @@ -6,7 +6,7 @@ LL | type Bar = impl Sized; | = note: `Bar` must be used in combination with a concrete type within the same module -error[E0307]: invalid `self` parameter type: Bar +error[E0307]: invalid `self` parameter type: `Bar` --> $DIR/arbitrary-self-opaque.rs:8:18 | LL | fn foo(self: Bar) {} diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs index 06a747273ab7f..fda044344517d 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.rs +++ b/tests/ui/simd/const-err-trumps-simd-err.rs @@ -5,7 +5,7 @@ #![feature(generic_arg_infer)] #![feature(core_intrinsics)] #![feature(repr_simd)] -#![feature(inline_const)] + use std::intrinsics::simd::*; #[repr(simd)] diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index 7300308781932..a81d8ebdf50c2 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -2,7 +2,6 @@ //@ ignore-emscripten FIXME(#45351) hits an LLVM assert #![feature(repr_simd, intrinsics)] -#![feature(inline_const)] #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/tests/ui/span/issue-27522.stderr b/tests/ui/span/issue-27522.stderr index c2de1562841c5..c57a100bbe227 100644 --- a/tests/ui/span/issue-27522.stderr +++ b/tests/ui/span/issue-27522.stderr @@ -1,4 +1,4 @@ -error[E0307]: invalid `self` parameter type: &SomeType +error[E0307]: invalid `self` parameter type: `&SomeType` --> $DIR/issue-27522.rs:6:22 | LL | fn handler(self: &SomeType); diff --git a/tests/ui/span/send-is-not-static-ensures-scoping.stderr b/tests/ui/span/send-is-not-static-ensures-scoping.stderr index bae0befcacaa7..c15547e84125b 100644 --- a/tests/ui/span/send-is-not-static-ensures-scoping.stderr +++ b/tests/ui/span/send-is-not-static-ensures-scoping.stderr @@ -16,6 +16,9 @@ error[E0597]: `y` does not live long enough | LL | let bad = { | --- borrow later stored here +LL | let x = 1; +LL | let y = &x; + | - binding `y` declared here ... LL | scoped(|| { | -- value captured here diff --git a/tests/ui/specialization/specialization-overlap-projection.stderr b/tests/ui/specialization/specialization-overlap-projection.current.stderr similarity index 89% rename from tests/ui/specialization/specialization-overlap-projection.stderr rename to tests/ui/specialization/specialization-overlap-projection.current.stderr index 708c0817fd96f..a69826fa96b08 100644 --- a/tests/ui/specialization/specialization-overlap-projection.stderr +++ b/tests/ui/specialization/specialization-overlap-projection.current.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap-projection.rs:7:12 + --> $DIR/specialization-overlap-projection.rs:10:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/specialization/specialization-overlap-projection.next.stderr b/tests/ui/specialization/specialization-overlap-projection.next.stderr new file mode 100644 index 0000000000000..ab040193fa4c7 --- /dev/null +++ b/tests/ui/specialization/specialization-overlap-projection.next.stderr @@ -0,0 +1,49 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-overlap-projection.rs:10:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:28:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +LL | impl Foo for ::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error[E0119]: conflicting implementations of trait `Foo` for type `u32` + --> $DIR/specialization-overlap-projection.rs:30:1 + | +LL | impl Foo for u32 {} + | ---------------- first implementation here +... +LL | impl Foo for ::Output {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error[E0282]: type annotations needed + --> $DIR/specialization-overlap-projection.rs:17:27 + | +LL | default type Output = bool; + | ^^^^ cannot infer type for associated type `::Output` + +error[E0282]: type annotations needed + --> $DIR/specialization-overlap-projection.rs:21:35 + | +LL | impl Assoc for u8 { type Output = u8; } + | ^^ cannot infer type for associated type `::Output` + +error[E0282]: type annotations needed + --> $DIR/specialization-overlap-projection.rs:23:36 + | +LL | impl Assoc for u16 { type Output = u16; } + | ^^^ cannot infer type for associated type `::Output` + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0119, E0282. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs index 66951b9d50c60..78e75f623c4bf 100644 --- a/tests/ui/specialization/specialization-overlap-projection.rs +++ b/tests/ui/specialization/specialization-overlap-projection.rs @@ -1,4 +1,7 @@ -//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[current] check-pass // Test that impls on projected self types can resolve overlap, even when the // projections involve specialization, so long as the associated type is @@ -12,14 +15,19 @@ trait Assoc { impl Assoc for T { default type Output = bool; + //[next]~^ ERROR type annotations needed } impl Assoc for u8 { type Output = u8; } +//[next]~^ ERROR type annotations needed impl Assoc for u16 { type Output = u16; } +//[next]~^ ERROR type annotations needed trait Foo {} impl Foo for u32 {} impl Foo for ::Output {} +//[next]~^ ERROR conflicting implementations of trait `Foo` for type `u32` impl Foo for ::Output {} +//[next]~^ ERROR conflicting implementations of trait `Foo` for type `u32` fn main() {} diff --git a/tests/ui/sse2.rs b/tests/ui/sse2.rs index fa6d79713b4bc..60570c566dea2 100644 --- a/tests/ui/sse2.rs +++ b/tests/ui/sse2.rs @@ -19,7 +19,7 @@ fn main() { assert!(cfg!(target_feature = "sse2"), "SSE2 was not detected as available on an x86 platform"); } - // check a negative case too -- allowed on x86, but not enabled by default - assert!(cfg!(not(target_feature = "avx2")), - "AVX2 shouldn't be detected as available by default on any platform"); + // check a negative case too -- certainly not enabled by default + assert!(cfg!(not(target_feature = "ferris_wheel")), + "🎡 shouldn't be detected as available by default on any platform"); } diff --git a/tests/ui/statics/nested_struct.rs b/tests/ui/statics/nested_struct.rs index f5819f50789c2..6745e10296241 100644 --- a/tests/ui/statics/nested_struct.rs +++ b/tests/ui/statics/nested_struct.rs @@ -9,7 +9,7 @@ pub struct Lint { pub name: &'static str, pub desc: &'static str, pub report_in_external_macro: bool, - pub is_loaded: bool, + pub is_externally_loaded: bool, pub crate_level_only: bool, } @@ -17,7 +17,7 @@ static FOO: &Lint = &Lint { name: &"foo", desc: "desc", report_in_external_macro: false, - is_loaded: true, + is_externally_loaded: true, crate_level_only: false, }; diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index dc24833c267c7..1a67c9438449b 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -11,15 +11,15 @@ ast-stats-1 Attribute 64 ( 1.0%) 2 32 ast-stats-1 - Normal 32 ( 0.5%) 1 ast-stats-1 - DocComment 32 ( 0.5%) 1 ast-stats-1 Local 80 ( 1.2%) 1 80 -ast-stats-1 Arm 96 ( 1.4%) 2 48 -ast-stats-1 ForeignItem 96 ( 1.4%) 1 96 -ast-stats-1 - Fn 96 ( 1.4%) 1 +ast-stats-1 ForeignItem 88 ( 1.3%) 1 88 +ast-stats-1 - Fn 88 ( 1.3%) 1 +ast-stats-1 Arm 96 ( 1.5%) 2 48 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 ast-stats-1 FieldDef 160 ( 2.4%) 2 80 ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 -ast-stats-1 - Expr 96 ( 1.4%) 3 +ast-stats-1 - Expr 96 ( 1.5%) 3 ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Variant 208 ( 3.1%) 2 104 @@ -28,7 +28,7 @@ ast-stats-1 - Trait 352 ( 5.3%) 4 ast-stats-1 AssocItem 352 ( 5.3%) 4 88 ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2 -ast-stats-1 GenericParam 480 ( 7.2%) 5 96 +ast-stats-1 GenericParam 480 ( 7.3%) 5 96 ast-stats-1 Pat 504 ( 7.6%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 @@ -53,7 +53,7 @@ ast-stats-1 - Impl 136 ( 2.1%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.2%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_624 +ast-stats-1 Total 6_616 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -65,9 +65,9 @@ ast-stats-2 ExprField 48 ( 0.7%) 1 48 ast-stats-2 WherePredicate 56 ( 0.8%) 1 56 ast-stats-2 - BoundPredicate 56 ( 0.8%) 1 ast-stats-2 Local 80 ( 1.1%) 1 80 +ast-stats-2 ForeignItem 88 ( 1.2%) 1 88 +ast-stats-2 - Fn 88 ( 1.2%) 1 ast-stats-2 Arm 96 ( 1.3%) 2 48 -ast-stats-2 ForeignItem 96 ( 1.3%) 1 96 -ast-stats-2 - Fn 96 ( 1.3%) 1 ast-stats-2 InlineAsm 120 ( 1.7%) 1 120 ast-stats-2 FnDecl 120 ( 1.7%) 5 24 ast-stats-2 Attribute 128 ( 1.8%) 4 32 @@ -86,7 +86,7 @@ ast-stats-2 - Trait 352 ( 4.9%) 4 ast-stats-2 AssocItem 352 ( 4.9%) 4 88 ast-stats-2 - Type 176 ( 2.4%) 2 ast-stats-2 - Fn 176 ( 2.4%) 2 -ast-stats-2 GenericParam 480 ( 6.6%) 5 96 +ast-stats-2 GenericParam 480 ( 6.7%) 5 96 ast-stats-2 Pat 504 ( 7.0%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 @@ -113,7 +113,7 @@ ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.8%) 2 ast-stats-2 - Use 544 ( 7.5%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_224 +ast-stats-2 Total 7_216 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size diff --git a/tests/ui/str/str-escape.stderr b/tests/ui/str/str-escape.stderr index 00fe5444e1a4e..c4aee2a110a5b 100644 --- a/tests/ui/str/str-escape.stderr +++ b/tests/ui/str/str-escape.stderr @@ -15,7 +15,7 @@ LL | let s = c"foo\ LL | |   bar | | ^ whitespace symbol '\u{a0}' is not skipped | |___| - | + | warning: whitespace symbol '\u{c}' is not skipped --> $DIR/str-escape.rs:26:16 @@ -25,7 +25,7 @@ LL | let s = b"a\ LL | | b"; | | ^- whitespace symbol '\u{c}' is not skipped | |____| - | + | warning: 3 warnings emitted diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs index a8418943ba4f3..7a9e1b3c1e497 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.rs +++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(generic_nonzero)] #![feature(transparent_unions)] use std::mem::size_of; diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr index fca62bd1c801b..64e93ffaffd60 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.stderr +++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr @@ -1,5 +1,5 @@ warning: method `dummy` is never used - --> $DIR/enum-null-pointer-opt.rs:11:18 + --> $DIR/enum-null-pointer-opt.rs:10:18 | LL | trait Trait { fn dummy(&self) { } } | ----- ^^^^^ diff --git a/tests/ui/structs-enums/struct-rec/issue-17431-2.stderr b/tests/ui/structs-enums/struct-rec/issue-17431-2.stderr index cdf51632acd0e..e818409366d6a 100644 --- a/tests/ui/structs-enums/struct-rec/issue-17431-2.stderr +++ b/tests/ui/structs-enums/struct-rec/issue-17431-2.stderr @@ -11,7 +11,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ struct Baz { q: Option> } LL | -LL | +LL | LL ~ struct Foo { q: Option> } | diff --git a/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr index 881bc2819369b..afe523939acd2 100644 --- a/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr +++ b/tests/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr @@ -16,7 +16,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ y: Box>, LL | } -LL | +LL | LL | struct B { LL ~ z: Box> | @@ -39,7 +39,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ y: Option>>>, LL | } -LL | +LL | LL | struct D { LL ~ z: Option>>>, | diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 50491d5ef3eb6..9c933a9ef1c4f 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(generic_nonzero)] #![feature(never_type)] #![feature(pointer_is_aligned_to)] #![feature(strict_provenance)] diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.rs b/tests/ui/suggestions/core-std-import-order-issue-83564.rs index 62b9b246cc81b..6f2bdd7a38af5 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.rs +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.rs @@ -2,7 +2,6 @@ // // This is a regression test for #83564. // For some reason, Rust 2018 or higher is required to reproduce the bug. -#![feature(generic_nonzero)] fn main() { //~^ HELP consider importing one of these items diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr index 56e10b9340c0b..8665cc6d87cf5 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: use of undeclared type `NonZero` - --> $DIR/core-std-import-order-issue-83564.rs:9:14 + --> $DIR/core-std-import-order-issue-83564.rs:8:14 | LL | let _x = NonZero::new(5u32).unwrap(); | ^^^^^^^ use of undeclared type `NonZero` diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index 9d6d29ec74eec..ae3a0391eea24 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -74,22 +74,30 @@ LL | struct Struct { error[E0599]: the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied --> $DIR/derive-trait-for-method-call.rs:40:15 | +LL | enum Enum { + | --------- doesn't satisfy `Enum: Clone` +... LL | struct Foo (X, Y); | ---------------- method `test` not found for this struct ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo, Instant>` due to unsatisfied trait bounds | -note: the following trait bounds were not satisfied: - `Instant: Default` - `Vec: Clone` - --> $DIR/derive-trait-for-method-call.rs:20:9 +note: trait bound `Instant: Default` was not satisfied + --> $DIR/derive-trait-for-method-call.rs:20:40 | LL | impl Foo { - | ^^^^^ ^^^^^^^ --------- - | | | - | | unsatisfied trait bound introduced here - | unsatisfied trait bound introduced here + | ^^^^^^^ --------- + | | + | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `Enum: Clone` + which is required by `Vec: Clone` +help: consider annotating `Enum` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | enum Enum { + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed index 232d1dd8138be..69780648ab666 100644 --- a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed +++ b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed @@ -12,7 +12,18 @@ impl Foo for S {} impl Bar for S {} fn test(foo: impl Foo + Bar) { - foo.hello(); //~ ERROR E0599 + foo.hello(); //~ ERROR no method named `hello` found +} + +trait Trait { + fn method(&self) {} +} + +impl Trait for fn() {} + +#[allow(dead_code)] +fn test2(f: impl Fn() -> (dyn std::fmt::Debug) + Trait) { + f.method(); //~ ERROR no method named `method` found } fn main() { diff --git a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs index ab25b362fedbb..f49512bdd62af 100644 --- a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs +++ b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs @@ -12,7 +12,18 @@ impl Foo for S {} impl Bar for S {} fn test(foo: impl Foo) { - foo.hello(); //~ ERROR E0599 + foo.hello(); //~ ERROR no method named `hello` found +} + +trait Trait { + fn method(&self) {} +} + +impl Trait for fn() {} + +#[allow(dead_code)] +fn test2(f: impl Fn() -> dyn std::fmt::Debug) { + f.method(); //~ ERROR no method named `method` found } fn main() { diff --git a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr index 3a6052448cb0f..0aced78ddacba 100644 --- a/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr +++ b/tests/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr @@ -12,6 +12,20 @@ help: the following trait defines an item `hello`, perhaps you need to restrict LL | fn test(foo: impl Foo + Bar) { | +++++ -error: aborting due to 1 previous error +error[E0599]: no method named `method` found for type parameter `impl Fn() -> dyn std::fmt::Debug` in the current scope + --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:26:7 + | +LL | fn test2(f: impl Fn() -> dyn std::fmt::Debug) { + | -------------------------------- method `method` not found for this type parameter +LL | f.method(); + | ^^^^^^ method not found in `impl Fn() -> dyn std::fmt::Debug` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method`, perhaps you need to restrict type parameter `impl Fn() -> dyn std::fmt::Debug` with it: + | +LL | fn test2(f: impl Fn() -> (dyn std::fmt::Debug) + Trait) { + | + +++++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/issue-84973-blacklist.rs b/tests/ui/suggestions/issue-84973-blacklist.rs index 6a35d779c1cda..edc0637636b57 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.rs +++ b/tests/ui/suggestions/issue-84973-blacklist.rs @@ -14,7 +14,7 @@ struct S; fn main() { f_copy("".to_string()); //~ ERROR: the trait bound `String: Copy` is not satisfied [E0277] f_clone(S); //~ ERROR: the trait bound `S: Clone` is not satisfied [E0277] - f_unpin(static || { yield; }); + f_unpin(#[coroutine] static || { yield; }); //~^ ERROR: cannot be unpinned [E0277] let cl = || (); diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index 3333822832856..4fd063e46926a 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -36,11 +36,11 @@ LL + #[derive(Clone)] LL | struct S; | -error[E0277]: `{static coroutine@$DIR/issue-84973-blacklist.rs:17:13: 17:22}` cannot be unpinned - --> $DIR/issue-84973-blacklist.rs:17:13 +error[E0277]: `{static coroutine@$DIR/issue-84973-blacklist.rs:17:26: 17:35}` cannot be unpinned + --> $DIR/issue-84973-blacklist.rs:17:26 | -LL | f_unpin(static || { yield; }); - | ------- ^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/issue-84973-blacklist.rs:17:13: 17:22}` +LL | f_unpin(#[coroutine] static || { yield; }); + | ------- ^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/issue-84973-blacklist.rs:17:26: 17:35}` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/issue-85347.rs b/tests/ui/suggestions/issue-85347.rs index d14cf07d915ed..95e76e76cfa8a 100644 --- a/tests/ui/suggestions/issue-85347.rs +++ b/tests/ui/suggestions/issue-85347.rs @@ -2,11 +2,13 @@ use std::ops::Deref; trait Foo { type Bar<'a>: Deref::Bar>; //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - //~| ERROR associated type bindings are not allowed here //~| HELP add missing - //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied //~| ERROR associated type bindings are not allowed here + //~| HELP consider removing this type binding + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied //~| HELP add missing + //~| ERROR associated type bindings are not allowed here + //~| HELP consider removing this type binding } fn main() {} diff --git a/tests/ui/suggestions/issue-85347.stderr b/tests/ui/suggestions/issue-85347.stderr index 45f87e539b4e6..de0aa09ce49c7 100644 --- a/tests/ui/suggestions/issue-85347.stderr +++ b/tests/ui/suggestions/issue-85347.stderr @@ -19,6 +19,11 @@ error[E0229]: associated type bindings are not allowed here | LL | type Bar<'a>: Deref::Bar>; | ^^^^^^^^^^^^^ associated type not allowed here + | +help: consider removing this type binding + | +LL | type Bar<'a>: Deref::Bar>; + | ~~~~~~~~~~~~~~~ error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied --> $DIR/issue-85347.rs:3:42 @@ -44,6 +49,10 @@ LL | type Bar<'a>: Deref::Bar>; | ^^^^^^^^^^^^^ associated type not allowed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider removing this type binding + | +LL | type Bar<'a>: Deref::Bar>; + | ~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/issue-99240-2.stderr b/tests/ui/suggestions/issue-99240-2.stderr index 00bffee652938..5b86bc9880f6a 100644 --- a/tests/ui/suggestions/issue-99240-2.stderr +++ b/tests/ui/suggestions/issue-99240-2.stderr @@ -8,7 +8,7 @@ LL | // Alias:: LL | || Unit(); | ||________^_- call expression requires function | |________| - | + | | help: `Alias::Unit` is a unit enum variant, and does not take parentheses to be constructed | diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index c0dc71df06e65..abbf56cfac86f 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -26,7 +26,7 @@ help: consider changing method `bar`'s `self` parameter to be `&self` LL | fn bar(self: &Self) {} | ~~~~~ -error[E0307]: invalid `self` parameter type: () +error[E0307]: invalid `self` parameter type: `()` --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18 | LL | fn bar(self: ()) {} diff --git a/tests/ui/suggestions/option-content-move2.rs b/tests/ui/suggestions/option-content-move2.rs index 88e8a5b7aeef0..b0104d9bafb79 100644 --- a/tests/ui/suggestions/option-content-move2.rs +++ b/tests/ui/suggestions/option-content-move2.rs @@ -1,8 +1,10 @@ struct NotCopyable; +#[derive(Clone)] +struct NotCopyableButCloneable; fn func H, H: FnMut()>(_: F) {} -fn parse() { +fn foo() { let mut var = None; func(|| { // Shouldn't suggest `move ||.as_ref()` here @@ -12,5 +14,15 @@ fn parse() { } }); } +fn bar() { + let mut var = None; + func(|| { + // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here + move || { + //~^ ERROR: cannot move out of `var` + var = Some(NotCopyableButCloneable); + } + }); +} fn main() {} diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr index 0297c031eccaf..be97cba17b900 100644 --- a/tests/ui/suggestions/option-content-move2.stderr +++ b/tests/ui/suggestions/option-content-move2.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure - --> $DIR/option-content-move2.rs:9:9 + --> $DIR/option-content-move2.rs:11:9 | LL | let mut var = None; | ------- captured outer variable @@ -15,6 +15,23 @@ LL | var = Some(NotCopyable); | variable moved due to use in closure | move occurs because `var` has type `Option`, which does not implement the `Copy` trait -error: aborting due to 1 previous error +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move2.rs:21:9 + | +LL | let mut var = None; + | ------- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | +LL | var = Some(NotCopyableButCloneable); + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `Option`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/suggestions/option-content-move3.rs b/tests/ui/suggestions/option-content-move3.rs new file mode 100644 index 0000000000000..a245309d97fdf --- /dev/null +++ b/tests/ui/suggestions/option-content-move3.rs @@ -0,0 +1,30 @@ +#[derive(Debug)] +struct NotCopyable; +#[derive(Debug, Clone)] +struct NotCopyableButCloneable; + +fn func H, H: FnMut()>(_: F) {} + +fn foo() { + let var = NotCopyable; + func(|| { + // Shouldn't suggest `move ||.as_ref()` here + move || { //~ ERROR cannot move out of `var` + let x = var; //~ ERROR cannot move out of `var` + println!("{x:?}"); + } + }); +} + +fn bar() { + let var = NotCopyableButCloneable; + func(|| { + // Shouldn't suggest `move ||.as_ref()` here + move || { //~ ERROR cannot move out of `var` + let x = var; //~ ERROR cannot move out of `var` + println!("{x:?}"); + } + }); +} + +fn main() {} diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr new file mode 100644 index 0000000000000..a20dcce1ee310 --- /dev/null +++ b/tests/ui/suggestions/option-content-move3.stderr @@ -0,0 +1,95 @@ +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:13:21 + | +LL | let var = NotCopyable; + | --- captured outer variable +... +LL | move || { + | ------- captured by this `FnMut` closure +LL | let x = var; + | ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait + | +note: if `NotCopyable` implemented `Clone`, you could clone the value + --> $DIR/option-content-move3.rs:2:1 + | +LL | struct NotCopyable; + | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = var; + | --- you could clone this value +help: consider borrowing here + | +LL | let x = &var; + | + + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:12:9 + | +LL | let var = NotCopyable; + | --- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | let x = var; + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait + | +note: if `NotCopyable` implemented `Clone`, you could clone the value + --> $DIR/option-content-move3.rs:2:1 + | +LL | struct NotCopyable; + | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = var; + | --- you could clone this value + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:24:21 + | +LL | let var = NotCopyableButCloneable; + | --- captured outer variable +... +LL | move || { + | ------- captured by this `FnMut` closure +LL | let x = var; + | ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let x = &var; + | + + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:23:9 + | +LL | let var = NotCopyableButCloneable; + | --- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | let x = var; + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait + | +help: clone the value before moving it into the closure + | +LL ~ { +LL + let value = var.clone(); +LL ~ move || { +LL ~ let x = value; +LL | println!("{x:?}"); +LL ~ } +LL + } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/suggestions/suggest-split-at-mut.rs b/tests/ui/suggestions/suggest-split-at-mut.rs index d294c20b8240e..61704abbd3649 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.rs +++ b/tests/ui/suggestions/suggest-split-at-mut.rs @@ -1,4 +1,4 @@ -fn main() { +fn foo() { let mut foo = [1, 2, 3, 4]; let a = &mut foo[2]; let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time @@ -6,3 +6,57 @@ fn main() { *b = 6; println!("{:?} {:?}", a, b); } + +fn bar() { + let mut foo = [1,2,3,4]; + let a = &mut foo[..2]; + let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable more than once at a time + a[0] = 5; + b[0] = 6; + println!("{:?} {:?}", a, b); +} + +fn baz() { + let mut foo = [1,2,3,4]; + let a = &foo[..2]; + let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + b[0] = 6; + println!("{:?} {:?}", a, b); +} + +fn qux() { + let mut foo = [1,2,3,4]; + let a = &mut foo[..2]; + let b = &foo[2..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + a[0] = 5; + println!("{:?} {:?}", a, b); +} + +fn bad() { + let mut foo = [1,2,3,4]; + let a = &foo[1]; + let b = &mut foo[2]; //~ ERROR cannot borrow `foo[_]` as mutable because it is also borrowed as immutable + *b = 6; + println!("{:?} {:?}", a, b); +} + +fn bat() { + let mut foo = [1,2,3,4]; + let a = &mut foo[1]; + let b = &foo[2]; //~ ERROR cannot borrow `foo[_]` as immutable because it is also borrowed as mutable + *a = 5; + println!("{:?} {:?}", a, b); +} + +fn ang() { + let mut foo = [1,2,3,4]; + let a = &mut foo[0..]; + let b = &foo[0..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + a[0] = 5; + println!("{:?} {:?}", a, b); +} + +fn main() { + foo(); + bar(); +} diff --git a/tests/ui/suggestions/suggest-split-at-mut.stderr b/tests/ui/suggestions/suggest-split-at-mut.stderr index c42f09e3201db..4502ec1f393ba 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.stderr +++ b/tests/ui/suggestions/suggest-split-at-mut.stderr @@ -8,9 +8,81 @@ LL | let b = &mut foo[3]; LL | *a = 5; | ------ first borrow later used here | - = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices - = help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices -error: aborting due to 1 previous error +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/suggest-split-at-mut.rs:13:18 + | +LL | let a = &mut foo[..2]; + | --- first mutable borrow occurs here +LL | let b = &mut foo[2..]; + | ^^^ second mutable borrow occurs here +LL | a[0] = 5; + | ---- first borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/suggest-split-at-mut.rs:22:18 + | +LL | let a = &foo[..2]; + | --- immutable borrow occurs here +LL | let b = &mut foo[2..]; + | ^^^ mutable borrow occurs here +LL | b[0] = 6; +LL | println!("{:?} {:?}", a, b); + | - immutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:30:14 + | +LL | let a = &mut foo[..2]; + | --- mutable borrow occurs here +LL | let b = &foo[2..]; + | ^^^ immutable borrow occurs here +LL | a[0] = 5; + | ---- mutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo[_]` as mutable because it is also borrowed as immutable + --> $DIR/suggest-split-at-mut.rs:38:13 + | +LL | let a = &foo[1]; + | ------- immutable borrow occurs here +LL | let b = &mut foo[2]; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | *b = 6; +LL | println!("{:?} {:?}", a, b); + | - immutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo[_]` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:46:13 + | +LL | let a = &mut foo[1]; + | ----------- mutable borrow occurs here +LL | let b = &foo[2]; + | ^^^^^^^ immutable borrow occurs here +LL | *a = 5; + | ------ mutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:54:14 + | +LL | let a = &mut foo[0..]; + | --- mutable borrow occurs here +LL | let b = &foo[0..]; + | ^^^ immutable borrow occurs here +LL | a[0] = 5; + | ---- mutable borrow later used here + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0499`. +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/suggestions/unnamable-types.rs b/tests/ui/suggestions/unnamable-types.rs index a4e32d7c80654..dd2c3536eb92e 100644 --- a/tests/ui/suggestions/unnamable-types.rs +++ b/tests/ui/suggestions/unnamable-types.rs @@ -1,7 +1,7 @@ // Test that we do not suggest to add type annotations for unnamable types. #![crate_type="lib"] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] const A = 5; //~^ ERROR: missing type for `const` item @@ -34,6 +34,6 @@ const F = S { t: foo }; //~| HELP: provide a type for the constant -const G = || -> i32 { yield 0; return 1; }; +const G = #[coroutine] || -> i32 { yield 0; return 1; }; //~^ ERROR: missing type for `const` item //~| NOTE: however, the inferred type diff --git a/tests/ui/suggestions/unnamable-types.stderr b/tests/ui/suggestions/unnamable-types.stderr index d003b91691c0f..6623678fd0c2d 100644 --- a/tests/ui/suggestions/unnamable-types.stderr +++ b/tests/ui/suggestions/unnamable-types.stderr @@ -52,14 +52,14 @@ LL | const F = S { t: foo }; error: missing type for `const` item --> $DIR/unnamable-types.rs:37:8 | -LL | const G = || -> i32 { yield 0; return 1; }; +LL | const G = #[coroutine] || -> i32 { yield 0; return 1; }; | ^ | -note: however, the inferred type `{coroutine@$DIR/unnamable-types.rs:37:11: 37:20}` cannot be named - --> $DIR/unnamable-types.rs:37:11 +note: however, the inferred type `{coroutine@$DIR/unnamable-types.rs:37:24: 37:33}` cannot be named + --> $DIR/unnamable-types.rs:37:24 | -LL | const G = || -> i32 { yield 0; return 1; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const G = #[coroutine] || -> i32 { yield 0; return 1; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.rs b/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.rs new file mode 100644 index 0000000000000..6a273997ee630 --- /dev/null +++ b/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.rs @@ -0,0 +1,35 @@ +#![feature(dyn_star)] //~ WARNING the feature `dyn_star` is incomplete + +use std::future::Future; + +pub fn dyn_func( + executor: impl FnOnce(T) -> dyn Future, +) -> Box dyn Future> { + Box::new(executor) //~ ERROR may not live long enough +} + +pub fn dyn_star_func( + executor: impl FnOnce(T) -> dyn* Future, +) -> Box dyn* Future> { + Box::new(executor) //~ ERROR may not live long enough +} + +trait Trait { + fn method(&self) {} +} + +impl Trait for fn() {} + +pub fn in_ty_param dyn std::fmt::Debug> (t: T) { + t.method(); + //~^ ERROR no method named `method` found for type parameter `T` +} + +fn with_sized &'static (dyn std::fmt::Debug) + ?Sized>() { + without_sized::(); + //~^ ERROR the size for values of type `T` cannot be known at compilation time +} + +fn without_sized &'static dyn std::fmt::Debug>() {} + +fn main() {} diff --git a/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.stderr b/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.stderr new file mode 100644 index 0000000000000..f7fc17ea24f18 --- /dev/null +++ b/tests/ui/suggestions/wrap-dyn-in-suggestion-issue-120223.stderr @@ -0,0 +1,78 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:1:12 + | +LL | #![feature(dyn_star)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0599]: no method named `method` found for type parameter `T` in the current scope + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:24:7 + | +LL | pub fn in_ty_param dyn std::fmt::Debug> (t: T) { + | - method `method` not found for this type parameter +LL | t.method(); + | ^^^^^^ method not found in `T` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: + | +LL | pub fn in_ty_param (dyn std::fmt::Debug) + Trait> (t: T) { + | + +++++++++ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:29:21 + | +LL | fn with_sized &'static (dyn std::fmt::Debug) + ?Sized>() { + | - this type parameter needs to be `Sized` +LL | without_sized::(); + | ^ doesn't have a size known at compile-time + | +note: required by an implicit `Sized` bound in `without_sized` + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:33:18 + | +LL | fn without_sized &'static dyn std::fmt::Debug>() {} + | ^ required by the implicit `Sized` requirement on this type parameter in `without_sized` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn with_sized &'static (dyn std::fmt::Debug) + ?Sized>() { +LL + fn with_sized &'static (dyn std::fmt::Debug)>() { + | +help: consider relaxing the implicit `Sized` restriction + | +LL | fn without_sized &'static (dyn std::fmt::Debug) + ?Sized>() {} + | + ++++++++++ + +error[E0310]: the parameter type `impl FnOnce(T) -> dyn Future` may not live long enough + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:8:5 + | +LL | Box::new(executor) + | ^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `impl FnOnce(T) -> dyn Future` must be valid for the static lifetime... + | ...so that the type `impl FnOnce(T) -> dyn Future` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | executor: impl FnOnce(T) -> (dyn Future) + 'static, + | + +++++++++++ + +error[E0310]: the parameter type `impl FnOnce(T) -> Future` may not live long enough + --> $DIR/wrap-dyn-in-suggestion-issue-120223.rs:14:5 + | +LL | Box::new(executor) + | ^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `impl FnOnce(T) -> Future` must be valid for the static lifetime... + | ...so that the type `impl FnOnce(T) -> Future` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | executor: impl FnOnce(T) -> (dyn* Future) + 'static, + | + +++++++++++ + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0277, E0310, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr index 74526b4dbc182..49a4db7491ed8 100644 --- a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr +++ b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr @@ -12,13 +12,6 @@ note: trait bound `(): Iterator` was not satisfied | LL | trait IteratorAlias = Iterator; | ------------- ^^^^^^^^ unsatisfied trait bound introduced here -note: trait bound `(): IteratorAlias` was not satisfied - --> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:9:9 - | -LL | impl Foo { - | ^^^^^^^^^^^^^ ------ - | | - | unsatisfied trait bound introduced here error: aborting due to 1 previous error diff --git a/tests/ui/traits/dyn-any-prefer-vtable.rs b/tests/ui/traits/dyn-any-prefer-vtable.rs new file mode 100644 index 0000000000000..ca9d655239d86 --- /dev/null +++ b/tests/ui/traits/dyn-any-prefer-vtable.rs @@ -0,0 +1,9 @@ +//@ run-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +fn main() { + let x: &dyn std::any::Any = &1i32; + assert_eq!(x.type_id(), std::any::TypeId::of::()); +} diff --git a/tests/ui/traits/issue-78372.rs b/tests/ui/traits/issue-78372.rs index 143325c097c13..b97835bbc57fd 100644 --- a/tests/ui/traits/issue-78372.rs +++ b/tests/ui/traits/issue-78372.rs @@ -6,7 +6,7 @@ impl DispatchFromDyn> for T {} //~ ERROR cannot find type `U` //~| ERROR the trait `DispatchFromDyn` may only be implemented for a coercion between structures trait Foo: X {} trait X { - fn foo(self: Smaht); //~ ERROR: invalid `self` + fn foo(self: Smaht); //~ ERROR: invalid `self` parameter type } trait Marker {} impl Marker for dyn Foo {} diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index edb07957c445c..58a4c229e5e64 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -79,7 +79,7 @@ LL | trait X { LL | fn foo(self: Smaht); | ^^^^^^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on -error[E0307]: invalid `self` parameter type: Smaht +error[E0307]: invalid `self` parameter type: `Smaht` --> $DIR/issue-78372.rs:9:18 | LL | fn foo(self: Smaht); diff --git a/tests/ui/traits/mutual-recursion-issue-75860.rs b/tests/ui/traits/mutual-recursion-issue-75860.rs index d7d7307b42431..65c3dd132c35a 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.rs +++ b/tests/ui/traits/mutual-recursion-issue-75860.rs @@ -6,10 +6,10 @@ pub fn iso(a: F1, b: F2) -> (Box B>, Box (Box::new(a), Box::new(b)) } pub fn iso_un_option() -> (Box B>, Box A>) { - let left = |o_a: Option<_>| o_a.unwrap(); + let left = |o_a: Option<_>| o_a.unwrap(); + //~^ ERROR overflow let right = |o_b: Option<_>| o_b.unwrap(); iso(left, right) - //~^ ERROR overflow } fn main() {} diff --git a/tests/ui/traits/mutual-recursion-issue-75860.stderr b/tests/ui/traits/mutual-recursion-issue-75860.stderr index 8f83bab003db3..272c56301bc84 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.stderr +++ b/tests/ui/traits/mutual-recursion-issue-75860.stderr @@ -1,12 +1,8 @@ -error[E0275]: overflow evaluating the requirement `Option<_>: Sized` - --> $DIR/mutual-recursion-issue-75860.rs:11:5 +error[E0275]: overflow assigning `_` to `Option<_>` + --> $DIR/mutual-recursion-issue-75860.rs:9:33 | -LL | iso(left, right) - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`) -note: required by an implicit `Sized` bound in `Option` - --> $SRC_DIR/core/src/option.rs:LL:COL +LL | let left = |o_a: Option<_>| o_a.unwrap(); + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs new file mode 100644 index 0000000000000..78dffcbf6abc3 --- /dev/null +++ b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +trait Local {} + +trait Overlap { fn f(); } +impl Overlap for Option where Self: Clone, { fn f() {} } +impl Overlap for Option where Self: Local, { fn f() {} } + +fn test() +where + Option: Clone + Local, +{ + as Overlap>::f(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr index 14e67727d0ba7..e880d05a4dd34 100644 --- a/tests/ui/traits/next-solver/coroutine.fail.stderr +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `{coroutine@$DIR/coroutine.rs:18:21: 18:23}: Coroutine` is not satisfied - --> $DIR/coroutine.rs:18:21 +error[E0277]: the trait bound `{coroutine@$DIR/coroutine.rs:20:9: 20:11}: Coroutine` is not satisfied + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ the trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:18:21: 18:23}` +LL | | yield (); +LL | | }, + | |_________^ the trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:28 @@ -18,19 +18,19 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine>::Yield == B` - --> $DIR/coroutine.rs:18:21 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Yield == B` + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ types differ +LL | | yield (); +LL | | }, + | |_________^ types differ | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:41 @@ -38,19 +38,19 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine) {} | ^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine>::Return == C` - --> $DIR/coroutine.rs:18:21 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Return == C` + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ types differ +LL | | yield (); +LL | | }, + | |_________^ types differ | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:52 diff --git a/tests/ui/traits/next-solver/coroutine.rs b/tests/ui/traits/next-solver/coroutine.rs index 2b5bf01cefd7d..1882a62cf29cc 100644 --- a/tests/ui/traits/next-solver/coroutine.rs +++ b/tests/ui/traits/next-solver/coroutine.rs @@ -15,18 +15,24 @@ fn needs_coroutine(_: impl Coroutine) {} #[cfg(fail)] fn main() { - needs_coroutine(|| { - //[fail]~^ ERROR Coroutine` is not satisfied - //[fail]~| ERROR as Coroutine>::Yield == B` - //[fail]~| ERROR as Coroutine>::Return == C` - yield (); - }); + needs_coroutine( + #[coroutine] + || { + //[fail]~^ ERROR Coroutine` is not satisfied + //[fail]~| ERROR as Coroutine>::Yield == B` + //[fail]~| ERROR as Coroutine>::Return == C` + yield (); + }, + ); } #[cfg(pass)] fn main() { - needs_coroutine(|_: A| { - let _: A = yield B; - C - }) + needs_coroutine( + #[coroutine] + |_: A| { + let _: A = yield B; + C + }, + ) } diff --git a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs deleted file mode 100644 index a0fe7f0d0a5ba..0000000000000 --- a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: -Znext-solver -// FIXME(-Znext-solver): This test is currently broken because the `deduce_closure_signature` -// is unable to look at nested obligations. -trait Foo { - fn test() -> impl Fn(u32) -> u32 { - |x| x.count_ones() - //~^ ERROR type annotations needed - } -} - -fn main() {} diff --git a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr deleted file mode 100644 index 3d7cd1af4677f..0000000000000 --- a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/deduce-closure-signature-after-normalization.rs:6:10 - | -LL | |x| x.count_ones() - | ^ - type must be known at this point - | -help: consider giving this closure parameter an explicit type - | -LL | |x: /* Type */| x.count_ones() - | ++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index 17c55fb4d49df..caa3bfc552eb3 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver //~^ ERROR cannot normalize `::Id: '_` -#![feature(generic_nonzero)] #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index 65e3370032522..76ae08fdb7a7e 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-transmute.rs:4:12 + --> $DIR/specialization-transmute.rs:3:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -11,31 +11,31 @@ LL | #![feature(specialization)] error: cannot normalize `::Id: '_` error[E0284]: type annotations needed: cannot satisfy `::Id == _` - --> $DIR/specialization-transmute.rs:16:23 + --> $DIR/specialization-transmute.rs:15:23 | LL | fn intu(&self) -> &Self::Id { | ^^^^^^^^^ cannot satisfy `::Id == _` error[E0284]: type annotations needed: cannot satisfy `T <: ::Id` - --> $DIR/specialization-transmute.rs:18:9 + --> $DIR/specialization-transmute.rs:17:9 | LL | self | ^^^^ cannot satisfy `T <: ::Id` error[E0284]: type annotations needed: cannot satisfy `::Id == Option>` - --> $DIR/specialization-transmute.rs:29:13 + --> $DIR/specialization-transmute.rs:28:13 | LL | let s = transmute::>>(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == Option>` | note: required by a bound in `transmute` - --> $DIR/specialization-transmute.rs:22:25 + --> $DIR/specialization-transmute.rs:21:25 | LL | fn transmute, U: Copy>(t: T) -> U { | ^^^^^^ required by this bound in `transmute` error[E0282]: type annotations needed - --> $DIR/specialization-transmute.rs:14:23 + --> $DIR/specialization-transmute.rs:13:23 | LL | default type Id = T; | ^ cannot infer type for associated type `::Id` diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr index 822fc91e43fea..141f565077a5b 100644 --- a/tests/ui/traits/track-obligations.stderr +++ b/tests/ui/traits/track-obligations.stderr @@ -2,7 +2,10 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b --> $DIR/track-obligations.rs:83:16 | LL | struct ALayer(C); - | ---------------- doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>` + | ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` +... +LL | struct AService; + | --------------- doesn't satisfy `>::Response = Res` ... LL | struct Client(C); | ---------------- method `check` not found for this struct @@ -10,27 +13,14 @@ LL | struct Client(C); LL | Client(()).check(); | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds | -note: trait bound ` as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` was not satisfied - --> $DIR/track-obligations.rs:35:14 - | -LL | pub trait ParticularServiceLayer: - | ---------------------- -LL | Layer>::Service> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here -note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied - --> $DIR/track-obligations.rs:71:16 +note: trait bound `>::Response = Res` was not satisfied + --> $DIR/track-obligations.rs:24:21 | -LL | impl Client - | --------- +LL | impl ParticularService for T + | ----------------- - LL | where -LL | ALayer: ParticularServiceLayer, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here -note: the trait `ParticularServiceLayer` must be implemented - --> $DIR/track-obligations.rs:34:1 - | -LL | / pub trait ParticularServiceLayer: -LL | | Layer>::Service> - | |____________________________________________________________________^ +LL | T: Service, + | ^^^^^^^^^^^^^^ unsatisfied trait bound introduced here error[E0271]: type mismatch resolving `>::Response == Res` --> $DIR/track-obligations.rs:87:11 diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.rs b/tests/ui/transmute/ambiguity-in-closure-arg.rs new file mode 100644 index 0000000000000..4c2d1ce2ad463 --- /dev/null +++ b/tests/ui/transmute/ambiguity-in-closure-arg.rs @@ -0,0 +1,11 @@ +// Minimized test for . + +struct Unconstrained(T); + +fn main() { + unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) }; + //~^ ERROR type annotations needed + // We unfortunately don't check `Wf(Unconstrained<_>)`, so we won't + // hit an ambiguity error before checking the transmute. That means + // we still may have inference variables in our transmute src. +} diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.stderr b/tests/ui/transmute/ambiguity-in-closure-arg.stderr new file mode 100644 index 0000000000000..24a10a6d210b4 --- /dev/null +++ b/tests/ui/transmute/ambiguity-in-closure-arg.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/ambiguity-in-closure-arg.rs:6:44 + | +LL | unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) }; + | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/coherence.stderr b/tests/ui/type-alias-impl-trait/coherence.stderr index 4462b70f782ba..266a532a1db19 100644 --- a/tests/ui/type-alias-impl-trait/coherence.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | | | - | | `AliasOfForeignType<()>` is not defined in the current crate + | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs index cd14bc1fd0985..0d9126d399334 100644 --- a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs +++ b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs @@ -9,6 +9,7 @@ mod gen { pub type CoroOnce = impl Coroutine; pub const fn const_coroutine(yielding: Y, returning: R) -> CoroOnce { + #[coroutine] move || { yield yielding; diff --git a/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs b/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs index 78a1d5116bedb..899e81ed562fc 100644 --- a/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs @@ -8,6 +8,7 @@ use std::pin::Pin; type RandCoroutine<'a> = impl Coroutine + 'a; fn rand_coroutine<'a>(rng: &'a ()) -> RandCoroutine<'a> { + #[coroutine] move || { let _rng = rng; loop { @@ -19,6 +20,7 @@ fn rand_coroutine<'a>(rng: &'a ()) -> RandCoroutine<'a> { pub type RandCoroutineWithIndirection<'c> = impl Coroutine + 'c; pub fn rand_coroutine_with_indirection<'a>(rng: &'a ()) -> RandCoroutineWithIndirection<'a> { fn helper<'b>(rng: &'b ()) -> impl 'b + Coroutine { + #[coroutine] move || { let _rng = rng; loop { diff --git a/tests/ui/type-alias-impl-trait/issue-94429.rs b/tests/ui/type-alias-impl-trait/issue-94429.rs index 306e73003fa98..11beed06a20cd 100644 --- a/tests/ui/type-alias-impl-trait/issue-94429.rs +++ b/tests/ui/type-alias-impl-trait/issue-94429.rs @@ -14,6 +14,7 @@ impl Runnable for Implementor { fn run(&mut self) -> Self::Coro { //~^ ERROR: type mismatch resolving + #[coroutine] move || { yield 1; } diff --git a/tests/ui/type-alias-impl-trait/issue-94429.stderr b/tests/ui/type-alias-impl-trait/issue-94429.stderr index 5d081e6b1eff5..4c2020becbe32 100644 --- a/tests/ui/type-alias-impl-trait/issue-94429.stderr +++ b/tests/ui/type-alias-impl-trait/issue-94429.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<{coroutine@$DIR/issue-94429.rs:17:9: 17:16} as Coroutine>::Yield == ()` +error[E0271]: type mismatch resolving `<{coroutine@$DIR/issue-94429.rs:18:9: 18:16} as Coroutine>::Yield == ()` --> $DIR/issue-94429.rs:15:26 | LL | fn run(&mut self) -> Self::Coro { diff --git a/tests/ui/type/type-check/unknown_type_for_closure.stderr b/tests/ui/type/type-check/unknown_type_for_closure.stderr index e5e29aabf374b..960c0eff8ea30 100644 --- a/tests/ui/type/type-check/unknown_type_for_closure.stderr +++ b/tests/ui/type/type-check/unknown_type_for_closure.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/unknown_type_for_closure.rs:2:13 + --> $DIR/unknown_type_for_closure.rs:2:14 | LL | let x = |b: Vec<_>| {}; - | ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>` + | ^^^^^^^^^ cannot infer type error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:6:14 diff --git a/tests/ui/typeck/ice-unexpected-region-123863.rs b/tests/ui/typeck/ice-unexpected-region-123863.rs new file mode 100644 index 0000000000000..d0242df5fd2fc --- /dev/null +++ b/tests/ui/typeck/ice-unexpected-region-123863.rs @@ -0,0 +1,9 @@ +const fn concat_strs() -> &'static str { +//~^ ERROR &'static str` is forbidden as the type of a const generic parameter + struct Inner; +//~^ ERROR &'static str` is forbidden as the type of a const generic parameter + Inner::concat_strs::<"a">::A +//~^ ERROR ambiguous associated type +} + +pub fn main() {} diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr new file mode 100644 index 0000000000000..08f1ede95b45f --- /dev/null +++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr @@ -0,0 +1,38 @@ +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/ice-unexpected-region-123863.rs:1:31 + | +LL | const fn concat_strs() -> &'static str { + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/ice-unexpected-region-123863.rs:3:27 + | +LL | struct Inner; + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error[E0223]: ambiguous associated type + --> $DIR/ice-unexpected-region-123863.rs:5:5 + | +LL | Inner::concat_strs::<"a">::A + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `concat_strs` implemented for `Inner<_>`, you could use the fully-qualified path + | +LL | as Example>::concat_strs::A + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/typeck/issue-100285.stderr b/tests/ui/typeck/issue-100285.stderr index 9c8685a77127b..c0deb63af59ac 100644 --- a/tests/ui/typeck/issue-100285.stderr +++ b/tests/ui/typeck/issue-100285.stderr @@ -49,7 +49,7 @@ LL ~ return Some(4); LL | } else { LL ~ return Some(5); LL | } -LL | +LL | LL ~ } LL ~ None | diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index 0983147a5f0c5..9598bc61352fd 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -34,7 +34,7 @@ LL | | .cloned() LL | | .collect(); | | -^^^^^^^ method cannot be called due to unsatisfied trait bounds | |_________| - | + | | = note: the following trait bounds were not satisfied: `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr index 7c2507754751f..c48d094daea20 100644 --- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -15,7 +15,7 @@ LL | fn dummy2(&self); = note: expected signature `fn(&&'a Bar<_>)` found signature `fn(&Bar<_>)` -error[E0307]: invalid `self` parameter type: isize +error[E0307]: invalid `self` parameter type: `isize` --> $DIR/ufcs-explicit-self-bad.rs:8:18 | LL | fn foo(self: isize, x: isize) -> isize { @@ -24,7 +24,7 @@ LL | fn foo(self: isize, x: isize) -> isize { = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0307]: invalid `self` parameter type: Bar +error[E0307]: invalid `self` parameter type: `Bar` --> $DIR/ufcs-explicit-self-bad.rs:19:18 | LL | fn foo(self: Bar, x: isize) -> isize { @@ -33,7 +33,7 @@ LL | fn foo(self: Bar, x: isize) -> isize { = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0307]: invalid `self` parameter type: &Bar +error[E0307]: invalid `self` parameter type: `&Bar` --> $DIR/ufcs-explicit-self-bad.rs:23:18 | LL | fn bar(self: &Bar, x: isize) -> isize { diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index b7e9e1baa7bb4..c0fce5c2aaadc 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -15,7 +15,7 @@ help: consider introducing a named lifetime parameter LL ~ fn main<'a>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, ... -LL | +LL | LL ~ let _: dyn Foo(&'a isize, &'a usize) -> &'a usize; | diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index 23aa18d7156ac..fc6f610ddd4c2 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -1,6 +1,9 @@ error[E0597]: `factorial` does not live long enough --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 | +LL | let mut factorial: Option u32>> = None; + | ------------- binding `factorial` declared here +LL | LL | let f = |x: u32| -> u32 { | --------------- value captured here LL | let g = factorial.as_ref().unwrap(); @@ -30,7 +33,9 @@ error[E0597]: `factorial` does not live long enough --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 | LL | let mut factorial: Option u32 + 'static>> = None; - | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` + | ------------- ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` + | | + | binding `factorial` declared here LL | LL | let f = |x: u32| -> u32 { | --------------- value captured here diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr index 782fa63280ed6..f8e9609cb1c5e 100644 --- a/tests/ui/union/union-borrow-move-parent-sibling.stderr +++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr @@ -54,7 +54,10 @@ note: if `MockVec` implemented `Clone`, you could clone the value --> $DIR/union-borrow-move-parent-sibling.rs:25:1 | LL | struct MockVec { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = (u.x.0).0; + | --------- you could clone this value help: consider borrowing here | LL | let a = &(u.x.0).0; diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr index 5ebb2716e5a06..d520fb00ea9d5 100644 --- a/tests/ui/union/union-move.stderr +++ b/tests/ui/union/union-move.stderr @@ -20,7 +20,10 @@ note: if `U1` implemented `Clone`, you could clone the value --> $DIR/union-move.rs:9:1 | LL | union U1 { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | move_out(x.f1_nocopy); + | ----------- you could clone this value error[E0382]: use of moved value: `x` --> $DIR/union-move.rs:42:18 @@ -44,7 +47,10 @@ note: if `U1` implemented `Clone`, you could clone the value --> $DIR/union-move.rs:9:1 | LL | union U1 { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | move_out(x.f2_nocopy); + | ----------- you could clone this value error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:49:18 diff --git a/tests/ui/unknown-language-item.rs b/tests/ui/unknown-language-item.rs index 20ffef71497c0..ce206d20358a1 100644 --- a/tests/ui/unknown-language-item.rs +++ b/tests/ui/unknown-language-item.rs @@ -3,7 +3,7 @@ #[lang = "foo"] fn bar() -> ! { -//~^^ ERROR definition of an unknown language item: `foo` +//~^^ ERROR definition of an unknown lang item: `foo` loop {} } diff --git a/tests/ui/unknown-language-item.stderr b/tests/ui/unknown-language-item.stderr index 1e0256867c562..832f134241844 100644 --- a/tests/ui/unknown-language-item.stderr +++ b/tests/ui/unknown-language-item.stderr @@ -1,8 +1,8 @@ -error[E0522]: definition of an unknown language item: `foo` +error[E0522]: definition of an unknown lang item: `foo` --> $DIR/unknown-language-item.rs:4:1 | LL | #[lang = "foo"] - | ^^^^^^^^^^^^^^^ definition of unknown language item `foo` + | ^^^^^^^^^^^^^^^ definition of unknown lang item `foo` error: aborting due to 1 previous error diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr index 187dd66b2fe59..bc9b3ea990384 100644 --- a/tests/ui/unop-move-semantics.stderr +++ b/tests/ui/unop-move-semantics.stderr @@ -33,6 +33,14 @@ LL | !x; ... LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:11:18 + | +LL | fn move_borrowed>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; + | -- you could clone this value error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/unop-move-semantics.rs:17:6 @@ -47,6 +55,15 @@ LL | !y; | ^ move out of `y` occurs here LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:11:18 + | +LL | fn move_borrowed>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; +LL | let n = &mut y; + | ------ you could clone this value error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/unop-move-semantics.rs:24:6 @@ -59,6 +76,14 @@ LL | !*m; | note: calling this operator moves the value --> $SRC_DIR/core/src/ops/bit.rs:LL:COL +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:20:24 + | +LL | fn illegal_dereference>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | !*m; + | -- you could clone this value error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/unop-move-semantics.rs:26:6 @@ -68,6 +93,15 @@ LL | !*n; | || | |move occurs because `*n` has type `T`, which does not implement the `Copy` trait | `*n` moved due to usage in operator + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:20:24 + | +LL | fn illegal_dereference>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | !*n; + | -- you could clone this value error: aborting due to 5 previous errors diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.rs b/tests/ui/unpretty/staged-api-invalid-path-108697.rs new file mode 100644 index 0000000000000..1b6ef24919145 --- /dev/null +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.rs @@ -0,0 +1,9 @@ +// issue: rust-lang/rust#108697 +// ICE: tcx.resolutions(()) is not supported for local crate -Zunpretty=mir +// on invalid module path with staged_api +//@ compile-flags: -Zunpretty=mir +//@ normalize-stderr-test: "The system cannot find the file specified." -> "No such file or directory" +#![feature(staged_api)] +#[path = "lol"] +mod foo; +//~^ ERROR couldn't read diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr new file mode 100644 index 0000000000000..9c6d1a042d755 --- /dev/null +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr @@ -0,0 +1,8 @@ +error: couldn't read $DIR/lol: No such file or directory (os error 2) + --> $DIR/staged-api-invalid-path-108697.rs:8:1 + | +LL | mod foo; + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr index 4515d313ec0a4..03cada07a9e3d 100644 --- a/tests/ui/variance/variance-issue-20533.stderr +++ b/tests/ui/variance/variance-issue-20533.stderr @@ -14,7 +14,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = foo(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:41:14 @@ -32,7 +35,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = bar(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:47:14 @@ -50,7 +56,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = baz(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:53:14 diff --git a/tests/ui/variance/variance-regions-unused-indirect.stderr b/tests/ui/variance/variance-regions-unused-indirect.stderr index ec4d480baab78..8cdbb3c0f5ebd 100644 --- a/tests/ui/variance/variance-regions-unused-indirect.stderr +++ b/tests/ui/variance/variance-regions-unused-indirect.stderr @@ -16,7 +16,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ Foo1(Box>) LL | } -LL | +LL | LL | enum Bar<'a> { LL ~ Bar1(Box>) | diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 0009ed0e34c89..08b5517aae22f 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -152,6 +152,7 @@ fn r#match() { } fn i_yield() { + #[coroutine] static || { yield yield yield yield yield yield yield yield yield; }; diff --git a/tests/ui/wf/closure-wf.rs b/tests/ui/wf/closure-wf.rs new file mode 100644 index 0000000000000..48baeb30ce59b --- /dev/null +++ b/tests/ui/wf/closure-wf.rs @@ -0,0 +1,11 @@ +trait Bound {} +struct NeedsBound(T); + +// Checks that we enforce that closure args are WF. + +fn constrain_inner FnOnce(&'a (), NeedsBound)>(_: T, _: F) {} + +fn main() { + constrain_inner(1u32, |&(), _| ()); + //~^ ERROR the trait bound `u32: Bound` is not satisfied +} diff --git a/tests/ui/wf/closure-wf.stderr b/tests/ui/wf/closure-wf.stderr new file mode 100644 index 0000000000000..4beef3bb7c577 --- /dev/null +++ b/tests/ui/wf/closure-wf.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `u32: Bound` is not satisfied + --> $DIR/closure-wf.rs:9:33 + | +LL | constrain_inner(1u32, |&(), _| ()); + | ^ the trait `Bound` is not implemented for `u32` + | +help: this trait has no implementations, consider adding one + --> $DIR/closure-wf.rs:1:1 + | +LL | trait Bound {} + | ^^^^^^^^^^^ +note: required by a bound in `NeedsBound` + --> $DIR/closure-wf.rs:2:22 + | +LL | struct NeedsBound(T); + | ^^^^^ required by this bound in `NeedsBound` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/triagebot.toml b/triagebot.toml index 903569bf44549..499ba6e470cda 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -529,6 +529,10 @@ cc = ["@compiler-errors", "@lcnr"] message = "changes to the core type system" cc = ["@compiler-errors", "@lcnr"] +[mentions."compiler/rustc_hir_analysis/src/fn_ctxt/inspect_obligations.rs"] +message = "changes to `inspect_obligations.rs`" +cc = ["@compiler-errors", "@lcnr"] + [mentions."compiler/rustc_middle/src/mir/interpret"] message = "Some changes occurred to the CTFE / Miri engine" cc = ["@rust-lang/miri"]