diff options
203 files changed, 3781 insertions, 2713 deletions
diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml index c2c0c11f008..6d050d98cb2 100644 --- a/.github/workflows/ghcr.yml +++ b/.github/workflows/ghcr.yml @@ -53,9 +53,9 @@ jobs: run: | # List of DockerHub images to mirror to ghcr.io images=( - # Mirrored because used by the mingw-check-tidy, which doesn't cache Docker images + # Mirrored because used by the tidy job, which doesn't cache Docker images "ubuntu:22.04" - # Mirrored because used by all linux CI jobs, including mingw-check-tidy + # Mirrored because used by all linux CI jobs, including tidy "moby/buildkit:buildx-stable-1" # Mirrored because used when CI is running inside a Docker container "alpine:3.4" diff --git a/bootstrap.example.toml b/bootstrap.example.toml index cc1ea796a02..b59f112bdfb 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -467,6 +467,15 @@ # Whether to use the precompiled stage0 libtest with compiletest. #build.compiletest-use-stage0-libtest = true +# Default value for the `--extra-checks` flag of tidy. +# +# See `./x test tidy --help` for details. +# +# Note that if any value is manually given to bootstrap such as +# `./x test tidy --extra-checks=js`, this value is ignored. +# Use `--extra-checks=''` to temporarily disable all extra checks. +#build.tidy-extra-checks = "" + # Indicates whether ccache is used when building certain artifacts (e.g. LLVM). # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use # a specific version. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 86f4497bfde..ac6daba3901 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1390,6 +1390,7 @@ impl Expr { path.clone(), TraitBoundModifiers::NONE, self.span, + Parens::No, ))), _ => None, } @@ -3366,6 +3367,13 @@ pub struct TraitRef { pub ref_id: NodeId, } +/// Whether enclosing parentheses are present or not. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum Parens { + Yes, + No, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct PolyTraitRef { /// The `'a` in `for<'a> Foo<&'a T>`. @@ -3378,6 +3386,10 @@ pub struct PolyTraitRef { pub trait_ref: TraitRef, pub span: Span, + + /// When `Yes`, the first and last character of `span` are an opening + /// and a closing paren respectively. + pub parens: Parens, } impl PolyTraitRef { @@ -3386,12 +3398,14 @@ impl PolyTraitRef { path: Path, modifiers: TraitBoundModifiers, span: Span, + parens: Parens, ) -> Self { PolyTraitRef { bound_generic_params: generic_params, modifiers, trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, span, + parens, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index f9076f1f53d..42de5b727c5 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1142,7 +1142,7 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, ) -> V::Result { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p; try_visit!(visit_modifiers(vis, modifiers)); try_visit!(visit_generic_params(vis, bound_generic_params)); try_visit!(vis.visit_trait_ref(trait_ref)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 26d7c0cd6d3..d14e27982ef 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1209,6 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: TraitBoundModifiers::NONE, trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, span: t.span, + parens: ast::Parens::No, }, itctx, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index c7f41fc3cb1..5d8ee07178d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -469,7 +469,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "`if let` guards are experimental", "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`" ); - gate_all!(let_chains, "`let` expressions in this position are unstable"); gate_all!( async_trait_bounds, "`async` trait bounds are unstable", diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 7c412d4fa89..1132402ea00 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -3,7 +3,10 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use super::{ + AcceptMapping, AttributeOrder, AttributeParser, NoArgsAttributeParser, OnDuplicate, + SingleAttributeParser, +}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; @@ -43,20 +46,10 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { pub(crate) struct ColdParser; -impl<S: Stage> SingleAttributeParser<S> for ColdParser { +impl<S: Stage> NoArgsAttributeParser<S> for ColdParser { const PATH: &[Symbol] = &[sym::cold]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - return None; - } - - Some(AttributeKind::Cold(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } pub(crate) struct ExportNameParser; @@ -194,39 +187,17 @@ impl<S: Stage> AttributeParser<S> for NakedParser { } pub(crate) struct TrackCallerParser; - -impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser { +impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser { const PATH: &[Symbol] = &[sym::track_caller]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - return None; - } - - Some(AttributeKind::TrackCaller(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; } pub(crate) struct NoMangleParser; - -impl<S: Stage> SingleAttributeParser<S> for NoMangleParser { - const PATH: &[rustc_span::Symbol] = &[sym::no_mangle]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; +impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser { + const PATH: &[Symbol] = &[sym::no_mangle]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - return None; - } - - Some(AttributeKind::NoMangle(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; } #[derive(Default)] diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 1c8fc5079da..5437803d781 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,38 +1,19 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct AsPtrParser; - -impl<S: Stage> SingleAttributeParser<S> for AsPtrParser { +impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - } - Some(AttributeKind::AsPtr(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr; } pub(crate) struct PubTransparentParser; -impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser { +impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - } - Some(AttributeKind::PubTransparent(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent; } diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index f6c7ac5e3a3..80808b90dc6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,31 +1,19 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct LoopMatchParser; -impl<S: Stage> SingleAttributeParser<S> for LoopMatchParser { +impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser { const PATH: &[Symbol] = &[sym::loop_match]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { - Some(AttributeKind::LoopMatch(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch; } pub(crate) struct ConstContinueParser; -impl<S: Stage> SingleAttributeParser<S> for ConstContinueParser { +impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser { const PATH: &[Symbol] = &[sym::const_continue]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { - Some(AttributeKind::ConstContinue(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue; } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index b3a9c69c055..f791d44e09a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,7 +17,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_feature::AttributeTemplate; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -229,6 +229,41 @@ pub(crate) enum AttributeOrder { KeepLast, } +/// An even simpler version of [`SingleAttributeParser`]: +/// now automatically check that there are no arguments provided to the attribute. +/// +/// [`WithoutArgs<T> where T: NoArgsAttributeParser`](WithoutArgs) implements [`SingleAttributeParser`]. +// +pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static { + const PATH: &[Symbol]; + const ON_DUPLICATE: OnDuplicate<S>; + + /// Create the [`AttributeKind`] given attribute's [`Span`]. + const CREATE: fn(Span) -> AttributeKind; +} + +pub(crate) struct WithoutArgs<T: NoArgsAttributeParser<S>, S: Stage>(PhantomData<(S, T)>); + +impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> { + fn default() -> Self { + Self(Default::default()) + } +} + +impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> { + const PATH: &[Symbol] = T::PATH; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } + Some(T::CREATE(cx.attr_span)) + } +} + type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind; /// Alternative to [`AttributeParser`] that automatically handles state management. diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 54f50445fbd..74fdff5d2e1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -1,22 +1,12 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct MayDangleParser; -impl<S: Stage> SingleAttributeParser<S> for MayDangleParser { +impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - } - Some(AttributeKind::MayDangle(cx.attr_span)) - } + const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 37104855623..6bccd0042a8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,11 +5,12 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_feature::{AttributeTemplate, template}; +use rustc_feature::template; use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use super::{AcceptMapping, AttributeParser, OnDuplicate}; +use crate::attributes::NoArgsAttributeParser; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -132,19 +133,10 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser { } pub(crate) struct ConstStabilityIndirectParser; -// FIXME(jdonszelmann): single word attribute group when we have these -impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser { +impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; - const TEMPLATE: AttributeTemplate = template!(Word); - - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - } - Some(AttributeKind::ConstStabilityIndirect) - } + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect; } #[derive(Default)] diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 940a2996851..1f655d69cc2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -37,7 +37,7 @@ use crate::attributes::stability::{ }; use crate::attributes::traits::SkipDuringMethodDispatchParser; use crate::attributes::transparency::TransparencyParser; -use crate::attributes::{AttributeParser as _, Combine, Single}; +use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; @@ -58,6 +58,7 @@ macro_rules! attribute_parsers { use super::*; type Combine<T> = super::Combine<T, Early>; type Single<T> = super::Single<T, Early>; + type WithoutArgs<T> = super::WithoutArgs<T, Early>; attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];); } @@ -65,6 +66,7 @@ macro_rules! attribute_parsers { use super::*; type Combine<T> = super::Combine<T, Late>; type Single<T> = super::Single<T, Late>; + type WithoutArgs<T> = super::WithoutArgs<T, Late>; attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];); } @@ -119,28 +121,28 @@ attribute_parsers!( // tidy-alphabetical-end // tidy-alphabetical-start - Single<AsPtrParser>, - Single<ColdParser>, - Single<ConstContinueParser>, - Single<ConstStabilityIndirectParser>, Single<DeprecationParser>, Single<ExportNameParser>, Single<InlineParser>, Single<LinkNameParser>, Single<LinkSectionParser>, - Single<LoopMatchParser>, - Single<MayDangleParser>, Single<MustUseParser>, - Single<NoMangleParser>, Single<OptimizeParser>, - Single<PubTransparentParser>, Single<RustcForceInlineParser>, Single<RustcLayoutScalarValidRangeEnd>, Single<RustcLayoutScalarValidRangeStart>, Single<RustcObjectLifetimeDefaultParser>, Single<SkipDuringMethodDispatchParser>, - Single<TrackCallerParser>, Single<TransparencyParser>, + Single<WithoutArgs<AsPtrParser>>, + Single<WithoutArgs<ColdParser>>, + Single<WithoutArgs<ConstContinueParser>>, + Single<WithoutArgs<ConstStabilityIndirectParser>>, + Single<WithoutArgs<LoopMatchParser>>, + Single<WithoutArgs<MayDangleParser>>, + Single<WithoutArgs<NoMangleParser>>, + Single<WithoutArgs<PubTransparentParser>>, + Single<WithoutArgs<TrackCallerParser>>, // tidy-alphabetical-end ]; ); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7ef04213d32..60cf4e28b5a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar { + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { return imm; } @@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => { - if from_backend_ty == to_backend_ty { - imm - } else { - bx.bitcast(imm, to_backend_ty) - } - } + (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 317b1229a90..76fa744361a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::{Span, Symbol, sym}; @@ -23,8 +23,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, - compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, - throw_unsup, throw_unsup_format, + compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -462,6 +462,44 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // (We know the value here in the machine of course, but this is the runtime of that code, // not the optimization stage.) sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, + + // We handle these here since Miri does not want to have them. + sym::assert_inhabited + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid => { + let ty = instance.args.type_at(0); + let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); + + let should_panic = !ecx + .tcx + .check_validity_requirement((requirement, ecx.typing_env().as_query_input(ty))) + .map_err(|_| err_inval!(TooGeneric))?; + + if should_panic { + let layout = ecx.layout_of(ty)?; + + let msg = match requirement { + // For *all* intrinsics we first check `is_uninhabited` to give a more specific + // error message. + _ if layout.is_uninhabited() => format!( + "aborted execution: attempted to instantiate uninhabited type `{ty}`" + ), + ValidityRequirement::Inhabited => bug!("handled earlier"), + ValidityRequirement::Zero => format!( + "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" + ), + ValidityRequirement::UninitMitigated0x01Fill => format!( + "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" + ), + ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), + }; + + Self::panic_nounwind(ecx, &msg)?; + // Skip the `return_to_block` at the end (we panicked, we do not return). + return interp_ok(None); + } + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d7cede71293..378ed6d0e10 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; -use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::{Symbol, sym}; @@ -17,8 +17,8 @@ use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy, - PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, - err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, + PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, + interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -372,41 +372,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.exact_div(&val, &size, dest)?; } - sym::assert_inhabited - | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => { - let ty = instance.args.type_at(0); - let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); - - let should_panic = !self - .tcx - .check_validity_requirement((requirement, self.typing_env.as_query_input(ty))) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - let layout = self.layout_of(ty)?; - - let msg = match requirement { - // For *all* intrinsics we first check `is_uninhabited` to give a more specific - // error message. - _ if layout.is_uninhabited() => format!( - "aborted execution: attempted to instantiate uninhabited type `{ty}`" - ), - ValidityRequirement::Inhabited => bug!("handled earlier"), - ValidityRequirement::Zero => format!( - "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" - ), - ValidityRequirement::UninitMitigated0x01Fill => format!( - "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" - ), - ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), - }; - - M::panic_nounwind(self, &msg)?; - // Skip the `return_to_block` at the end (we panicked, we do not return). - return interp_ok(true); - } - } sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 3b36bb85985..ff822b52a8d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! /// /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. - fn get_alloc_raw( + pub fn get_alloc_raw( &self, id: AllocId, ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> { @@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the /// allocation. - fn get_alloc_raw_mut( + /// + /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. + pub fn get_alloc_raw_mut( &mut self, id: AllocId, ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> { @@ -976,15 +978,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } - /// Handle the effect an FFI call might have on the state of allocations. - /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all reachable provenances as exposed - /// and overwrite them with `Provenance::WILDCARD`. - /// - /// The allocations in `ids` are assumed to be already exposed. - pub fn prepare_for_native_call(&mut self, ids: Vec<AllocId>) -> InterpResult<'tcx> { + /// Visit all allocations reachable from the given start set, by recursively traversing the + /// provenance information of those allocations. + pub fn visit_reachable_allocs( + &mut self, + start: Vec<AllocId>, + mut visit: impl FnMut(&mut Self, AllocId, &AllocInfo) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let mut done = FxHashSet::default(); - let mut todo = ids; + let mut todo = start; while let Some(id) = todo.pop() { if !done.insert(id) { // We already saw this allocation before, don't process it again. @@ -992,31 +994,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let info = self.get_alloc_info(id); - // If there is no data behind this pointer, skip this. - if !matches!(info.kind, AllocKind::LiveData) { - continue; - } - - // Expose all provenances in this allocation, and add them to `todo`. - let alloc = self.get_alloc_raw(id)?; - for prov in alloc.provenance().provenances() { - M::expose_provenance(self, prov)?; - if let Some(id) = prov.get_alloc_id() { - todo.push(id); + // Recurse, if there is data here. + // Do this *before* invoking the callback, as the callback might mutate the + // allocation and e.g. replace all provenance by wildcards! + if matches!(info.kind, AllocKind::LiveData) { + let alloc = self.get_alloc_raw(id)?; + for prov in alloc.provenance().provenances() { + if let Some(id) = prov.get_alloc_id() { + todo.push(id); + } } } - // Also expose the provenance of the interpreter-level allocation, so it can - // be read by FFI. The `black_box` is defensive programming as LLVM likes - // to (incorrectly) optimize away ptr2int casts whose result is unused. - std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); - - // Prepare for possible write from native code if mutable. - if info.mutbl.is_mut() { - self.get_alloc_raw_mut(id)? - .0 - .prepare_for_native_write() - .map_err(|e| e.to_interp_error(id))?; - } + + // Call the callback. + visit(self, id, &info)?; } interp_ok(()) } @@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { todo.extend(static_roots(self)); while let Some(id) = todo.pop() { if reachable.insert(id) { - // This is a new allocation, add the allocation it points to `todo`. + // This is a new allocation, add the allocations it points to `todo`. + // We only need to care about `alloc_map` memory here, as entirely unchanged + // global memory cannot point to memory relevant for the leak check. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()), diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 36649a36070..1b4db7adc27 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -88,6 +88,7 @@ use std::fmt::Display; use std::intrinsics::unlikely; use std::path::Path; use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::{Duration, Instant}; use std::{fs, process}; @@ -99,12 +100,15 @@ use tracing::warn; use crate::fx::FxHashMap; use crate::outline; +use crate::sync::AtomicU64; bitflags::bitflags! { #[derive(Clone, Copy)] struct EventFilter: u16 { const GENERIC_ACTIVITIES = 1 << 0; const QUERY_PROVIDERS = 1 << 1; + /// Store detailed instant events, including timestamp and thread ID, + /// per each query cache hit. Note that this is quite expensive. const QUERY_CACHE_HITS = 1 << 2; const QUERY_BLOCKED = 1 << 3; const INCR_CACHE_LOADS = 1 << 4; @@ -113,16 +117,20 @@ bitflags::bitflags! { const FUNCTION_ARGS = 1 << 6; const LLVM = 1 << 7; const INCR_RESULT_HASHING = 1 << 8; - const ARTIFACT_SIZES = 1 << 9; + const ARTIFACT_SIZES = 1 << 9; + /// Store aggregated counts of cache hits per query invocation. + const QUERY_CACHE_HIT_COUNTS = 1 << 10; const DEFAULT = Self::GENERIC_ACTIVITIES.bits() | Self::QUERY_PROVIDERS.bits() | Self::QUERY_BLOCKED.bits() | Self::INCR_CACHE_LOADS.bits() | Self::INCR_RESULT_HASHING.bits() | - Self::ARTIFACT_SIZES.bits(); + Self::ARTIFACT_SIZES.bits() | + Self::QUERY_CACHE_HIT_COUNTS.bits(); const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits(); + const QUERY_CACHE_HIT_COMBINED = Self::QUERY_CACHE_HITS.bits() | Self::QUERY_CACHE_HIT_COUNTS.bits(); } } @@ -134,6 +142,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ ("generic-activity", EventFilter::GENERIC_ACTIVITIES), ("query-provider", EventFilter::QUERY_PROVIDERS), ("query-cache-hit", EventFilter::QUERY_CACHE_HITS), + ("query-cache-hit-count", EventFilter::QUERY_CACHE_HITS), ("query-blocked", EventFilter::QUERY_BLOCKED), ("incr-cache-load", EventFilter::INCR_CACHE_LOADS), ("query-keys", EventFilter::QUERY_KEYS), @@ -411,13 +420,24 @@ impl SelfProfilerRef { #[inline(never)] #[cold] fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) { - profiler_ref.instant_query_event( - |profiler| profiler.query_cache_hit_event_kind, - query_invocation_id, - ); + if profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) { + profiler_ref + .profiler + .as_ref() + .unwrap() + .increment_query_cache_hit_counters(QueryInvocationId(query_invocation_id.0)); + } + if unlikely(profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { + profiler_ref.instant_query_event( + |profiler| profiler.query_cache_hit_event_kind, + query_invocation_id, + ); + } } - if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { + // We check both kinds of query cache hit events at once, to reduce overhead in the + // common case (with self-profile disabled). + if unlikely(self.event_filter_mask.intersects(EventFilter::QUERY_CACHE_HIT_COMBINED)) { cold_call(self, query_invocation_id); } } @@ -489,6 +509,35 @@ impl SelfProfilerRef { self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s)) } + /// Store query cache hits to the self-profile log. + /// Should be called once at the end of the compilation session. + /// + /// The cache hits are stored per **query invocation**, not **per query kind/type**. + /// `analyzeme` can later deduplicate individual query labels from the QueryInvocationId event + /// IDs. + pub fn store_query_cache_hits(&self) { + if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) { + let profiler = self.profiler.as_ref().unwrap(); + let query_hits = profiler.query_hits.read(); + let builder = EventIdBuilder::new(&profiler.profiler); + let thread_id = get_thread_id(); + for (query_invocation, hit_count) in query_hits.iter().enumerate() { + let hit_count = hit_count.load(Ordering::Relaxed); + // No need to record empty cache hit counts + if hit_count > 0 { + let event_id = + builder.from_label(StringId::new_virtual(query_invocation as u64)); + profiler.profiler.record_integer_event( + profiler.query_cache_hit_count_event_kind, + event_id, + thread_id, + hit_count, + ); + } + } + } + } + #[inline] pub fn enabled(&self) -> bool { self.profiler.is_some() @@ -537,6 +586,19 @@ pub struct SelfProfiler { string_cache: RwLock<FxHashMap<String, StringId>>, + /// Recording individual query cache hits as "instant" measureme events + /// is incredibly expensive. Instead of doing that, we simply aggregate + /// cache hit *counts* per query invocation, and then store the final count + /// of cache hits per invocation at the end of the compilation session. + /// + /// With this approach, we don't know the individual thread IDs and timestamps + /// of cache hits, but it has very little overhead on top of `-Zself-profile`. + /// Recording the cache hits as individual events made compilation 3-5x slower. + /// + /// Query invocation IDs should be monotonic integers, so we can store them in a vec, + /// rather than using a hashmap. + query_hits: RwLock<Vec<AtomicU64>>, + query_event_kind: StringId, generic_activity_event_kind: StringId, incremental_load_result_event_kind: StringId, @@ -544,6 +606,8 @@ pub struct SelfProfiler { query_blocked_event_kind: StringId, query_cache_hit_event_kind: StringId, artifact_size_event_kind: StringId, + /// Total cache hits per query invocation + query_cache_hit_count_event_kind: StringId, } impl SelfProfiler { @@ -573,6 +637,7 @@ impl SelfProfiler { let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); let artifact_size_event_kind = profiler.alloc_string("ArtifactSize"); + let query_cache_hit_count_event_kind = profiler.alloc_string("QueryCacheHitCount"); let mut event_filter_mask = EventFilter::empty(); @@ -618,6 +683,8 @@ impl SelfProfiler { query_blocked_event_kind, query_cache_hit_event_kind, artifact_size_event_kind, + query_cache_hit_count_event_kind, + query_hits: Default::default(), }) } @@ -627,6 +694,25 @@ impl SelfProfiler { self.profiler.alloc_string(s) } + /// Store a cache hit of a query invocation + pub fn increment_query_cache_hit_counters(&self, id: QueryInvocationId) { + // Fast path: assume that the query was already encountered before, and just record + // a cache hit. + let mut guard = self.query_hits.upgradable_read(); + let query_hits = &guard; + let index = id.0 as usize; + if index < query_hits.len() { + // We only want to increment the count, no other synchronization is required + query_hits[index].fetch_add(1, Ordering::Relaxed); + } else { + // If not, we need to extend the query hit map to the highest observed ID + guard.with_upgraded(|vec| { + vec.resize_with(index + 1, || AtomicU64::new(0)); + vec[index] = AtomicU64::from(1); + }); + } + } + /// Gets a `StringId` for the given string. This method makes sure that /// any strings going through it will only be allocated once in the /// profiling data. diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 14b8cc90d97..a333f2c7cb7 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -195,6 +195,7 @@ impl<'a> ExtCtxt<'a> { }, trait_ref: self.trait_ref(path), span, + parens: ast::Parens::No, } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 99aa376626d..c607a3a3652 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -195,38 +195,6 @@ impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> { } } -/// Currently used by macro_rules! compilation to extract a little information from the `Failure` -/// case. -pub(crate) struct FailureForwarder<'matcher> { - expected_token: Option<&'matcher Token>, -} - -impl<'matcher> FailureForwarder<'matcher> { - pub(crate) fn new() -> Self { - Self { expected_token: None } - } -} - -impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> { - type Failure = (Token, u32, &'static str); - - fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { - (tok, position, msg) - } - - fn description() -> &'static str { - "failure-forwarder" - } - - fn set_expected_token(&mut self, tok: &'matcher Token) { - self.expected_token = Some(tok); - } - - fn get_expected_token(&self) -> Option<&'matcher Token> { - self.expected_token - } -} - pub(super) fn emit_frag_parse_err( mut e: Diag<'_>, parser: &Parser<'_>, @@ -321,7 +289,7 @@ enum ExplainDocComment { }, } -pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { +fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { err.subdiagnostic(ExplainDocComment::Outer { span }); @@ -333,7 +301,7 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For /// other tokens, this is "unexpected token...". -pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { +fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index dc2d46c4a14..bbdff866feb 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -105,8 +105,6 @@ //! stored when entering a macro definition starting from the state in which the meta-variable is //! bound. -use std::iter; - use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; @@ -190,29 +188,22 @@ struct MacroState<'a> { ops: SmallVec<[KleeneToken; 1]>, } -/// Checks that meta-variables are used correctly in a macro definition. +/// Checks that meta-variables are used correctly in one rule of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints /// - `node_id` is used to emit lints -/// - `span` is used when no spans are available -/// - `lhses` and `rhses` should have the same length and represent the macro definition +/// - `lhs` and `rhs` represent the rule pub(super) fn check_meta_variables( psess: &ParseSess, node_id: NodeId, - span: Span, - lhses: &[TokenTree], - rhses: &[TokenTree], + lhs: &TokenTree, + rhs: &TokenTree, ) -> Result<(), ErrorGuaranteed> { - if lhses.len() != rhses.len() { - psess.dcx().span_bug(span, "length mismatch between LHSes and RHSes") - } let mut guar = None; - for (lhs, rhs) in iter::zip(lhses, rhses) { - let mut binders = Binders::default(); - check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); - check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); - } + let mut binders = Binders::default(); + check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); guar.map_or(Ok(()), Err) } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 802e43209a5..3f1fc841ea3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -536,8 +536,6 @@ impl TtParser { // The separator matches the current token. Advance past it. mp.idx += 1; self.next_mps.push(mp); - } else { - track.set_expected_token(separator); } } &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 432ab324740..dad2fd99ef2 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -19,12 +19,13 @@ use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, }; -use rustc_parse::parser::{ParseNtResult, Parser, Recovery}; +use rustc_parse::exp; +use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym}; +use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; use super::macro_parser::{NamedMatches, NamedParseResult}; @@ -34,8 +35,6 @@ use crate::base::{ SyntaxExtensionKind, TTMacroExpander, }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; -use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; -use crate::mbe::macro_parser::NamedMatch::*; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::transcribe::transcribe; use crate::mbe::{self, KleeneOp, macro_check}; @@ -168,11 +167,6 @@ pub(super) trait Tracker<'matcher> { fn recovery() -> Recovery { Recovery::Forbidden } - - fn set_expected_token(&mut self, _tok: &'matcher Token) {} - fn get_expected_token(&self) -> Option<&'matcher Token> { - None - } } /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to @@ -360,11 +354,6 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( Err(CanRetry::Yes) } -// Note that macro-by-example's input is also matched against a token tree: -// $( $lhs:tt => $rhs:tt );+ -// -// Holy self-referential! - /// Converts a macro item into a syntax extension. pub fn compile_declarative_macro( sess: &Session, @@ -390,157 +379,66 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), Vec::new()); - let lhs_nm = Ident::new(sym::lhs, span); - let rhs_nm = Ident::new(sym::rhs, span); - let tt_spec = NonterminalKind::TT; let macro_rules = macro_def.macro_rules; + let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; - // Parse the macro_rules! invocation - - // The pattern that macro_rules matches. - // The grammar for macro_rules! is: - // $( $lhs:tt => $rhs:tt );+ - // ...quasiquoting this would be nice. - // These spans won't matter, anyways - let argument_gram = vec![ - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![ - mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec }, - mbe::TokenTree::token(token::FatArrow, span), - mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec }, - ], - separator: Some(Token::new( - if macro_rules { token::Semi } else { token::Comma }, - span, - )), - kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span), - num_captures: 2, - }, - ), - // to phase into semicolon-termination instead of semicolon-separation - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![mbe::TokenTree::token( - if macro_rules { token::Semi } else { token::Comma }, - span, - )], - separator: None, - kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span), - num_captures: 0, - }, - ), - ]; - // Convert it into `MatcherLoc` form. - let argument_gram = mbe::macro_parser::compute_locs(&argument_gram); - - let create_parser = || { - let body = macro_def.body.tokens.clone(); - Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS) - }; - - let parser = create_parser(); - let mut tt_parser = - TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro })); - let argument_map = - match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) { - Success(m) => m, - Failure(()) => { - debug!("failed to parse macro tt"); - // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it - // with another one that gives us the information we need. - // For this we need to reclone the macro body as the previous parser consumed it. - let retry_parser = create_parser(); - - let mut track = diagnostics::FailureForwarder::new(); - let parse_result = - tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track); - let Failure((token, _, msg)) = parse_result else { - unreachable!("matcher returned something other than Failure after retry"); - }; - - let s = parse_failure_msg(&token, track.get_expected_token()); - let sp = token.span.substitute_dummy(span); - let mut err = sess.dcx().struct_span_err(sp, s); - err.span_label(sp, msg); - annotate_doc_comment(&mut err, sess.source_map(), sp); - let guar = err.emit(); - return dummy_syn_ext(guar); - } - Error(sp, msg) => { - let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg); - return dummy_syn_ext(guar); - } - ErrorReported(guar) => { - return dummy_syn_ext(guar); - } - }; + let body = macro_def.body.tokens.clone(); + let mut p = Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS); + // Don't abort iteration early, so that multiple errors can be reported. let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); - // Extract the arguments: - let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { - MatchedSeq(s) => s - .iter() - .map(|m| { - if let MatchedSingle(ParseNtResult::Tt(tt)) = m { - let tt = mbe::quoted::parse( - &TokenStream::new(vec![tt.clone()]), - true, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); - // We don't handle errors here, the driver will abort - // after parsing/expansion. We can report every error in every macro this way. - check_emission(check_lhs_nt_follows(sess, node_id, &tt)); - return tt; - } - sess.dcx().span_bug(span, "wrong-structured lhs") - }) - .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(span, "wrong-structured lhs"), - }; + let mut lhses = Vec::new(); + let mut rhses = Vec::new(); - let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { - MatchedSeq(s) => s - .iter() - .map(|m| { - if let MatchedSingle(ParseNtResult::Tt(tt)) = m { - return mbe::quoted::parse( - &TokenStream::new(vec![tt.clone()]), - false, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); - } - sess.dcx().span_bug(span, "wrong-structured rhs") - }) - .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(span, "wrong-structured rhs"), - }; - - for rhs in &rhses { - check_emission(check_rhs(sess, rhs)); + while p.token != token::Eof { + let lhs_tt = p.parse_token_tree(); + let lhs_tt = mbe::quoted::parse( + &TokenStream::new(vec![lhs_tt]), + true, // LHS + sess, + node_id, + features, + edition, + ) + .pop() + .unwrap(); + // We don't handle errors here, the driver will abort after parsing/expansion. We can + // report every error in every macro this way. + check_emission(check_lhs_nt_follows(sess, node_id, &lhs_tt)); + check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(&lhs_tt))); + if let Err(e) = p.expect(exp!(FatArrow)) { + return dummy_syn_ext(e.emit()); + } + let rhs_tt = p.parse_token_tree(); + let rhs_tt = mbe::quoted::parse( + &TokenStream::new(vec![rhs_tt]), + false, // RHS + sess, + node_id, + features, + edition, + ) + .pop() + .unwrap(); + check_emission(check_rhs(sess, &rhs_tt)); + check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); + lhses.push(lhs_tt); + rhses.push(rhs_tt); + if p.token == token::Eof { + break; + } + if let Err(e) = p.expect(exp_sep) { + return dummy_syn_ext(e.emit()); + } } - // Don't abort iteration early, so that errors for multiple lhses can be reported. - for lhs in &lhses { - check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); + if lhses.is_empty() { + let guar = sess.dcx().span_err(span, "macros must contain at least one rule"); + return dummy_syn_ext(guar); } - check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(macro_rules)); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index db67c507b70..83be3241b12 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -265,6 +265,8 @@ declare_features! ( (accepted, keylocker_x86, "1.89.0", Some(134813)), /// Allows `'a: { break 'a; }`. (accepted, label_break_value, "1.65.0", Some(48594)), + /// Allows `if/while p && let q = r && ...` chains. + (accepted, let_chains, "1.88.0", Some(53667)), /// Allows `let...else` statements. (accepted, let_else, "1.65.0", Some(87335)), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 269a9c60d86..efd8bde71d7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -550,8 +550,6 @@ declare_features! ( (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. (incomplete, lazy_type_alias, "1.72.0", Some(112792)), - /// Allows `if/while p && let q = r && ...` chains. - (unstable, let_chains, "1.37.0", Some(53667)), /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 7eb896f0bf1..573af01a62d 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,12 +1,11 @@ use std::assert_matches::assert_matches; use std::ops::ControlFlow; -use hir::intravisit::{self, Visitor}; -use hir::{GenericParamKind, HirId, Node}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, AmbigArg}; +use rustc_hir::intravisit::{self, Visitor, VisitorExt}; +use rustc_hir::{self as hir, AmbigArg, GenericParamKind, HirId, Node}; +use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::{Span, Symbol, kw}; @@ -212,7 +211,19 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } - _ => None, + + // All of these nodes have no parent from which to inherit generics. + Node::Item(_) | Node::ForeignItem(_) => None, + + // Params don't really have generics, but we use it when instantiating their value paths. + Node::GenericParam(_) => None, + + Node::Synthetic => span_bug!( + tcx.def_span(def_id), + "synthetic HIR should have its `generics_of` explicitly fed" + ), + + _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"), }; enum Defaults { 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 f335c0e2f40..f17ef01ee03 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2459,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // type a projection. let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. } | hir::OpaqueTyOrigin::AsyncFn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => true, + } => Some(parent), hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2474,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => false, + | hir::OpaqueTyOrigin::TyAlias { .. } => None, }; self.lower_opaque_ty(opaque_ty.def_id, in_trait) @@ -2594,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] - fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> { let tcx = self.tcx(); let lifetimes = tcx.opaque_captured_lifetimes(def_id); debug!(?lifetimes); - // If this is an RPITIT and we are using the new RPITIT lowering scheme, we - // generate the def_id of an associated type for the trait and return as - // type a projection. - let def_id = if in_trait { - tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + // If this is an RPITIT and we are using the new RPITIT lowering scheme, + // do a linear search to map this to the synthetic associated type that + // it will be lowered to. + let def_id = if let Some(parent_def_id) = in_trait { + *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id) + .iter() + .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + opaque_def_id.expect_local() == def_id + } + _ => unreachable!(), + }) + .unwrap() } else { def_id.to_def_id() }; @@ -2627,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); debug!(?args); - if in_trait { + if in_trait.is_some() { Ty::new_projection_from_args(tcx, def_id, args) } else { Ty::new_opaque(tcx, def_id, args) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 95663204ec3..b694d3dd49b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -504,6 +504,7 @@ pub trait LintContext { /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] + #[track_caller] fn opt_span_lint<S: Into<MultiSpan>>( &self, lint: &'static Lint, @@ -542,6 +543,7 @@ pub trait LintContext { /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] + #[track_caller] fn span_lint<S: Into<MultiSpan>>( &self, lint: &'static Lint, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a206f71e153..0627f70507c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -3,6 +3,7 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -10,6 +11,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::{self, Ty, adjustment}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; +use rustc_span::edition::Edition::Edition2015; use rustc_span::{BytePos, Span, Symbol, kw, sym}; use tracing::instrument; @@ -1034,6 +1036,31 @@ pub(crate) struct UnusedParens { /// `1 as (i32) < 2` parses to ExprKind::Lt /// `1 as i32 < 2` parses to i32::<2[missing angle bracket] parens_in_cast_in_lt: Vec<ast::NodeId>, + /// Ty nodes in this map are in TypeNoBounds position. Any bounds they + /// contain may be ambiguous w/r/t trailing `+` operators. + in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>, +} + +/// Whether parentheses may be omitted from a type without resulting in ambiguity. +/// +/// ``` +/// type Example = Box<dyn Fn() -> &'static (dyn Send) + Sync>; +/// ``` +/// +/// Here, `&'static (dyn Send) + Sync` is a `TypeNoBounds`. As such, it may not directly +/// contain `ImplTraitType` or `TraitObjectType` which is why `(dyn Send)` is parenthesized. +/// However, an exception is made for `ImplTraitTypeOneBound` and `TraitObjectTypeOneBound`. +/// The following is accepted because there is no `+`. +/// +/// ``` +/// type Example = Box<dyn Fn() -> &'static dyn Send>; +/// ``` +enum NoBoundsException { + /// The type must be parenthesized. + None, + /// The type is the last bound of the containing type expression. If it has exactly one bound, + /// parentheses around the type are unnecessary. + OneBound, } impl_lint_pass!(UnusedParens => [UNUSED_PARENS]); @@ -1277,23 +1304,100 @@ impl EarlyLintPass for UnusedParens { ); } ast::TyKind::Paren(r) => { - match &r.kind { - ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) - if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - _ => { - let spans = if !ty.span.from_expansion() { + let unused_parens = match &r.kind { + ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => { + match self.in_no_bounds_pos.get(&ty.id) { + Some(NoBoundsException::None) => false, + Some(NoBoundsException::OneBound) => bounds.len() <= 1, + None => true, + } + } + ast::TyKind::BareFn(b) => { + !self.with_self_ty_parens || b.generic_params.is_empty() + } + _ => true, + }; + + if unused_parens { + let spans = (!ty.span.from_expansion()) + .then(|| { r.span .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + }) + .flatten(); + + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + } + + self.with_self_ty_parens = false; + } + ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => { + self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound); + } + ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { + for i in 0..bounds.len() { + let is_last = i == bounds.len() - 1; + + if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] { + let fn_with_explicit_ret_ty = if let [.., segment] = + &*poly_trait_ref.trait_ref.path.segments + && let Some(args) = segment.args.as_ref() + && let ast::GenericArgs::Parenthesized(paren_args) = &**args + && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output + { + self.in_no_bounds_pos.insert( + ret_ty.id, + if is_last { + NoBoundsException::OneBound + } else { + NoBoundsException::None + }, + ); + + true } else { - None + false }; - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + + // In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is + // parsed as a path, so parens are necessary to disambiguate. See + // - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and + // - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018 + let dyn2015_exception = cx.sess().psess.edition == Edition2015 + && matches!(ty.kind, ast::TyKind::TraitObject(..)) + && i == 0 + && poly_trait_ref + .trait_ref + .path + .segments + .first() + .map(|s| s.ident.name == kw::PathRoot) + .unwrap_or(false); + + if let ast::Parens::Yes = poly_trait_ref.parens + && (is_last || !fn_with_explicit_ret_ty) + && !dyn2015_exception + { + let s = poly_trait_ref.span; + let spans = (!s.from_expansion()).then(|| { + ( + s.with_hi(s.lo() + rustc_span::BytePos(1)), + s.with_lo(s.hi() - rustc_span::BytePos(1)), + ) + }); + + self.emit_unused_delims( + cx, + poly_trait_ref.span, + spans, + "type", + (false, false), + false, + ); + } } } - self.with_self_ty_parens = false; } _ => {} } @@ -1303,6 +1407,10 @@ impl EarlyLintPass for UnusedParens { <Self as UnusedDelimLint>::check_item(self, cx, item) } + fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) { + self.in_no_bounds_pos.clear(); + } + fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { use rustc_ast::{WhereBoundPredicate, WherePredicateKind}; if let WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index c21ab3ab56f..5821ffa3a30 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -413,7 +413,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { "Query {name} cannot be both `feedable` and `eval_always`." ); feedable_queries.extend(quote! { - #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, }); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 4198b198ab1..d2cadc96b63 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -799,7 +799,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> /// Initialize all previously uninitialized bytes in the entire allocation, and set /// provenance of everything to `Wildcard`. Before calling this, make sure all /// provenance in this allocation is exposed! - pub fn prepare_for_native_write(&mut self) -> AllocResult { + pub fn prepare_for_native_access(&mut self) { let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) }; // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be. for chunk in self.init_mask.range_as_init_chunks(full_range) { @@ -814,13 +814,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> // Set provenance of all bytes to wildcard. self.provenance.write_wildcards(self.len()); - - // Also expose the provenance of the interpreter-level allocation, so it can - // be written by FFI. The `black_box` is defensive programming as LLVM likes - // to (incorrectly) optimize away ptr2int casts whose result is unused. - std::hint::black_box(self.get_bytes_unchecked_raw_mut().expose_provenance()); - - Ok(()) } /// Remove all provenance in the given memory range. 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 c9525df1f79..63608947eb3 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -120,7 +120,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { } } - /// Check if here is ptr-sized provenance at the given index. + /// Check if there is ptr-sized provenance at the given index. /// Does not mean anything for bytewise provenance! But can be useful as an optimization. pub fn get_ptr(&self, offset: Size) -> Option<Prov> { self.ptrs.get(&offset).copied() diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index eb981177fa2..8c20e71e26a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -440,7 +440,6 @@ rustc_queries! { query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } - feedable } query opaque_types_defined_by( @@ -1093,13 +1092,6 @@ rustc_queries! { separate_provide_extern } - /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding - /// associated item. - query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { - desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } - cache_on_disk_if { true } - } - /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index bda8dcadbce..730c1147684 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> { }, /// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression. LoopMatch { - /// The state variable that is updated, and also the scrutinee of the match. + /// The state variable that is updated. + /// The `match_data.scrutinee` is the same variable, but with a different span. state: ExprId, region_scope: region::Scope, - arms: Box<[ArmId]>, - match_span: Span, + match_data: Box<LoopMatchMatchData>, }, /// Special expression representing the `let` part of an `if let` or similar construct /// (including `if let` guards in match arms, and let-chains formed by `&&`). @@ -599,6 +599,14 @@ pub struct Arm<'tcx> { pub span: Span, } +/// The `match` part of a `#[loop_match]` +#[derive(Clone, Debug, HashStable)] +pub struct LoopMatchMatchData { + pub scrutinee: ExprId, + pub arms: Box<[ArmId]>, + pub span: Span, +} + #[derive(Copy, Clone, Debug, HashStable)] pub enum LogicalOp { /// The `&&` operator. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c9ef723aea4..dcfa6c4db32 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -2,6 +2,7 @@ use super::{ AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; +use crate::thir::LoopMatchMatchData; /// Every `walk_*` method uses deconstruction to access fields of structs and /// enums. This will result in a compile error if a field is added, which makes @@ -83,7 +84,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(pat); } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => { + LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. } + | Match { scrutinee, ref arms, .. } => { visitor.visit_expr(&visitor.thir()[scrutinee]); for &arm in &**arms { visitor.visit_arm(&visitor.thir()[arm]); diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index fe3d072fa88..82b883a99a1 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }) } - ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => { + ExprKind::LoopMatch { + state, + region_scope, + match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee }, + } => { // Intuitively, this is a combination of a loop containing a labeled block // containing a match. // @@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Logic for `match`. let scrutinee_place_builder = - unpack!(body_block = this.as_place_builder(body_block, state)); - let scrutinee_span = this.thir.exprs[state].span; + unpack!(body_block = this.as_place_builder(body_block, scrutinee)); + let scrutinee_span = this.thir.exprs[scrutinee].span; let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); @@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { move |this| { this.in_breakable_scope(None, state_place, expr_span, |this| { Some(this.in_const_continuable_scope( - arms.clone(), + Box::from(arms), built_tree.clone(), state_place, expr_span, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9600067a85f..2c29b862841 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2970,6 +2970,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Constructor::Wildcard => true, + // Opaque patterns must not be matched on structurally. + Constructor::Opaque(_) => false, + // These we may eventually support: Constructor::Struct | Constructor::Ref @@ -2980,8 +2983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()), // These should never occur here: - Constructor::Opaque(_) - | Constructor::Never + Constructor::Never | Constructor::NonExhaustive | Constructor::Hidden | Constructor::Missing diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 20e836f6bf2..16b49bf384c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1230,7 +1230,6 @@ pub(crate) struct ConstContinueMissingValue { #[derive(Diagnostic)] #[diag(mir_build_const_continue_unknown_jump_target)] -#[note] pub(crate) struct ConstContinueUnknownJumpTarget { #[primary_span] pub span: Span, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 5197e93fda7..b694409f327 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> { data: region::ScopeData::Node, }, - arms: arms.iter().map(|a| self.convert_arm(a)).collect(), - match_span: block_body_expr.span, + match_data: Box::new(LoopMatchMatchData { + scrutinee: self.mirror_expr(scrutinee), + arms: arms.iter().map(|a| self.convert_arm(a)).collect(), + span: block_body_expr.span, + }), } } else { let block_ty = self.typeck_results.node_type(body.hir_id); 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 41fbabc2539..b7b160c738d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -6,7 +6,7 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::Level; use rustc_middle::bug; @@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { ExprKind::Match { scrutinee, box ref arms, match_source } => { self.check_match(scrutinee, arms, match_source, ex.span); } + ExprKind::LoopMatch { + match_data: box LoopMatchMatchData { scrutinee, box ref arms, span }, + .. + } => { + self.check_match(scrutinee, arms, MatchSource::Normal, span); + } ExprKind::Let { box ref pat, expr } => { self.check_let(pat, Some(expr), ex.span); } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 1507b6b8c06..5efc4be2de2 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*body, depth_lvl + 2); print_indented!(self, ")", depth_lvl); } - LoopMatch { state, region_scope, match_span, arms } => { + LoopMatch { state, region_scope, match_data } => { print_indented!(self, "LoopMatch {", depth_lvl); print_indented!(self, "state:", depth_lvl + 1); self.print_expr(*state, depth_lvl + 2); print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); - print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1); - - print_indented!(self, "arms: [", depth_lvl + 1); - for arm_id in arms.iter() { - self.print_arm(*arm_id, depth_lvl + 2); + print_indented!(self, "match_data:", depth_lvl + 1); + print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2); + print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3); + print_indented!(self, "scrutinee:", depth_lvl + 3); + self.print_expr(match_data.scrutinee, depth_lvl + 4); + + print_indented!(self, "arms: [", depth_lvl + 3); + for arm_id in match_data.arms.iter() { + self.print_arm(*arm_id, depth_lvl + 4); } - print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "]", depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 2); print_indented!(self, "}", depth_lvl); } Let { expr, pat } => { diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs index d1d1dc97307..33a87cb9873 100644 --- a/compiler/rustc_mir_transform/src/check_enums.rs +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -120,6 +120,7 @@ enum EnumCheckType<'tcx> { }, } +#[derive(Debug, Copy, Clone)] struct TyAndSize<'tcx> { pub ty: Ty<'tcx>, pub size: Size, @@ -337,7 +338,7 @@ fn insert_direct_enum_check<'tcx>( let invalid_discr_block_data = BasicBlockData::new(None, false); let invalid_discr_block = basic_blocks.push(invalid_discr_block_data); let block_data = &mut basic_blocks[current_block]; - let discr = insert_discr_cast_to_u128( + let discr_place = insert_discr_cast_to_u128( tcx, local_decls, block_data, @@ -348,13 +349,34 @@ fn insert_direct_enum_check<'tcx>( source_info, ); + // Mask out the bits of the discriminant type. + let mask = discr.size.unsigned_int_max(); + let discr_masked = + local_decls.push(LocalDecl::with_source_info(tcx.types.u128, source_info)).into(); + let rvalue = Rvalue::BinaryOp( + BinOp::BitAnd, + Box::new(( + Operand::Copy(discr_place), + Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_u128(mask), tcx.types.u128), + })), + )), + ); + block_data + .statements + .push(Statement::new(source_info, StatementKind::Assign(Box::new((discr_masked, rvalue))))); + // Branch based on the discriminant value. block_data.terminator = Some(Terminator { source_info, kind: TerminatorKind::SwitchInt { - discr: Operand::Copy(discr), + discr: Operand::Copy(discr_masked), targets: SwitchTargets::new( - discriminants.into_iter().map(|discr| (discr, new_block)), + discriminants + .into_iter() + .map(|discr_val| (discr.size.truncate(discr_val), new_block)), invalid_discr_block, ), }, @@ -371,7 +393,7 @@ fn insert_direct_enum_check<'tcx>( })), expected: true, target: new_block, - msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))), + msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr_masked))), // This calls panic_invalid_enum_construction, which is #[rustc_nounwind]. // We never want to insert an unwind into unsafe code, because unwinding could // make a failing UB check turn into much worse UB when we start unwinding. diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0a839d91404..81d7b7ba02c 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -239,7 +239,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); body_def.generics_of(tcx.generics_of(coroutine_def_id).clone()); body_def.param_env(tcx.param_env(coroutine_def_id)); - body_def.predicates_of(tcx.predicates_of(coroutine_def_id)); + body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); // The type of the coroutine is the `by_move_coroutine_ty`. body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty)); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f6e0b08b140..af9f8735549 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -512,6 +512,8 @@ parse_leading_underscore_unicode_escape_label = invalid start of unicode escape parse_left_arrow_operator = unexpected token: `<-` .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` +parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later + parse_lifetime_after_mut = lifetime must precede `mut` .suggestion = place the lifetime before `mut` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0f0c5434800..7f1b0991f0c 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1779,6 +1779,13 @@ pub(crate) struct AsyncBoundModifierIn2015 { } #[derive(Diagnostic)] +#[diag(parse_let_chain_pre_2024)] +pub(crate) struct LetChainPre2024 { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_self_argument_pointer)] pub(crate) struct SelfArgumentPointer { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3cedc86dc0d..3d89530f914 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4117,7 +4117,7 @@ impl MutVisitor for CondChecker<'_> { LetChainsPolicy::AlwaysAllowed => (), LetChainsPolicy::EditionDependent { current_edition } => { if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() { - self.parser.psess.gated_spans.gate(sym::let_chains, span); + self.parser.dcx().emit_err(errors::LetChainPre2024 { span }); } } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8221c709027..0c57a8cc5e1 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -305,8 +305,13 @@ impl<'a> Parser<'a> { let removal_span = kw.span.with_hi(self.token.span.lo()); let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - let kind = - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; + let kind = self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )?; let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), @@ -333,7 +338,13 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? + self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )? } } } else if self.eat_keyword(exp!(Impl)) { @@ -413,9 +424,13 @@ impl<'a> Parser<'a> { let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, path) if maybe_bounds => { - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) - } + TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path( + ThinVec::new(), + path, + lo, + true, + ast::Parens::Yes, + ), // For `('a) + …`, we know that `'a` in type position already lead to an error being // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and // other irrelevant consequential errors. @@ -495,12 +510,14 @@ impl<'a> Parser<'a> { path: ast::Path, lo: Span, parse_plus: bool, + parens: ast::Parens, ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new( generic_params, path, TraitBoundModifiers::NONE, lo.to(self.prev_token.span), + parens, ); let bounds = vec![GenericBound::Trait(poly_trait_ref)]; self.parse_remaining_bounds(bounds, parse_plus) @@ -826,7 +843,7 @@ impl<'a> Parser<'a> { Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) + self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No) } else { // Just a type path. Ok(TyKind::Path(None, path)) @@ -892,10 +909,10 @@ impl<'a> Parser<'a> { fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; let leading_token = self.prev_token; - let has_parens = self.eat(exp!(OpenParen)); + let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No }; let bound = if self.token.is_lifetime() { - self.parse_generic_lt_bound(lo, has_parens)? + self.parse_generic_lt_bound(lo, parens)? } else if self.eat_keyword(exp!(Use)) { // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of // lifetimes and ident params (including SelfUpper). These are validated later @@ -904,7 +921,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, has_parens, &leading_token)? + self.parse_generic_ty_bound(lo, parens, &leading_token)? }; Ok(bound) @@ -914,10 +931,14 @@ impl<'a> Parser<'a> { /// ```ebnf /// LT_BOUND = LIFETIME /// ``` - fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> { + fn parse_generic_lt_bound( + &mut self, + lo: Span, + parens: ast::Parens, + ) -> PResult<'a, GenericBound> { let lt = self.expect_lifetime(); let bound = GenericBound::Outlives(lt); - if has_parens { + if let ast::Parens::Yes = parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P<GenericBound>)`? self.recover_paren_lifetime(lo)?; @@ -1090,7 +1111,7 @@ impl<'a> Parser<'a> { fn parse_generic_ty_bound( &mut self, lo: Span, - has_parens: bool, + parens: ast::Parens, leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; @@ -1116,7 +1137,7 @@ impl<'a> Parser<'a> { // e.g. `T: for<'a> 'a` or `T: [const] 'a`. if self.token.is_lifetime() { let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); - return self.parse_generic_lt_bound(lo, has_parens); + return self.parse_generic_lt_bound(lo, parens); } if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { @@ -1183,7 +1204,7 @@ impl<'a> Parser<'a> { self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?; } - if has_parens { + if let ast::Parens::Yes = parens { // Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)` if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { @@ -1203,7 +1224,7 @@ impl<'a> Parser<'a> { } let poly_trait = - PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span)); + PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens); Ok(GenericBound::Trait(poly_trait)) } diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 7d80e54bf87..7be75ea88ac 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -259,4 +259,5 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() { alloc(tcx, &mut string_cache) } + tcx.sess.prof.store_query_cache_hits(); } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 58942474e32..aa818cc9c46 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -432,6 +432,7 @@ resolve_undeclared_label = resolve_underscore_lifetime_is_reserved = `'_` cannot be used here .label = `'_` is a reserved lifetime name + .help = use another lifetime specifier resolve_unexpected_res_change_ty_to_const_param_sugg = you might have meant to write a const parameter here diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 509907435d6..b34bcb38f84 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[derive(Diagnostic)] #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +#[help] pub(crate) struct UnderscoreLifetimeIsReserved { #[primary_span] #[label] diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e7b8c988cd4..6230b8cfbec 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3832,6 +3832,7 @@ fn mk_where_bound_predicate( ref_id: DUMMY_NODE_ID, }, span: DUMMY_SP, + parens: ast::Parens::No, })], }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 93c39f3ec8b..d6537d49be7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1775,7 +1775,6 @@ symbols! { resume, return_position_impl_trait_in_trait, return_type_notation, - rhs, riscv_target_feature, rlib, ropi, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index 66733d5d4b8..b01ca989282 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index ecf68ddff8c..bc7e445f3f8 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index e205aef8285..4dc76f0936c 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index bcb328020ee..9dc44aa05cc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 37c888ba514..10072f8092d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 3096c4d14ad..a7f4e0eabb0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index 9e406af53b5..af5704b51ba 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index f145c5b8c14..26ee6a68c6a 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index d3ead0d61b3..176d308de91 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -44,6 +44,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + match evaluate_host_effect_from_item_bounds(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), @@ -153,7 +159,9 @@ fn evaluate_host_effect_from_bounds<'tcx>( } } -fn evaluate_host_effect_from_item_bounds<'tcx>( +/// Assembles constness bounds from `~const` item bounds on alias types, which only +/// hold if the `~const` where bounds also hold and the parent trait is `~const`. +fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { @@ -232,6 +240,63 @@ fn evaluate_host_effect_from_item_bounds<'tcx>( } } +/// Assembles constness bounds "normal" item bounds on aliases, which may include +/// unconditionally `const` bounds that are *not* conditional and thus always hold. +fn evaluate_host_effect_from_item_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let tcx = infcx.tcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + let mut consider_ty = obligation.predicate.self_ty(); + while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() { + for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) { + let bound_clause = clause.kind(); + let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else { + continue; + }; + let data = bound_clause.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } + + let is_match = + infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); + } + } + } + + if kind != ty::Projection { + break; + } + + consider_ty = alias_ty.self_ty(); + } + + if let Some(data) = candidate { + Ok(match_candidate(selcx, obligation, data, true, |_, _| {}) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + fn evaluate_host_effect_from_builtin_impls<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index f14a45aa1e3..a65f9b347dc 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,9 +1,8 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, - associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; @@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::AssocItemContainer::Impl, } } -struct RPITVisitor { - rpits: FxIndexSet<LocalDefId>, +struct RPITVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + synthetics: Vec<LocalDefId>, + data: DefPathData, + disambiguator: DisambiguatorState, } -impl<'tcx> Visitor<'tcx> for RPITVisitor { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { - if let hir::TyKind::OpaqueDef(opaq) = ty.kind - && self.rpits.insert(opaq.def_id) - { - for bound in opaq.bounds { - intravisit::walk_param_bound(self, bound); - } - } - intravisit::walk_ty(self, ty) +impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result { + self.synthetics.push(associated_type_for_impl_trait_in_trait( + self.tcx, + opaque.def_id, + self.data, + &mut self.disambiguator, + )); + intravisit::walk_opaque_ty(self, opaque) } } @@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { + let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let mut visitor = RPITVisitor { + tcx, + synthetics: vec![], + data, + disambiguator: DisambiguatorState::with(parent_def_id, data, 0), + }; visitor.visit_fn_ret_ty(output); - - tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { - tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() - })) + tcx.arena.alloc_from_iter( + visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()), + ) } else { &[] } @@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn( let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[]; }; - tcx.arena.alloc_from_iter( tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( move |&trait_assoc_def_id| { @@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn( fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, + data: DefPathData, + disambiguator: &mut DisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait( let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); - // Collect all opaque types in return position for the method and use - // the index as the disambiguator to make an unique def path. - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap()); - let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap(); - let span = tcx.def_span(opaque_ty_def_id); // Also use the method name to create an unique def path. - let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); let trait_assoc_ty = tcx.at(span).create_def( trait_def_id, // No name because this is an anonymous associated type. None, DefKind::AssocTy, Some(data), - &mut DisambiguatorState::with(trait_def_id, data, disambiguator), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 4536f555443..4e3f76de49e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1098,115 +1098,6 @@ impl<T: ?Sized> Box<T> { pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self { unsafe { Self::from_raw(ptr.as_ptr()) } } -} - -impl<T: ?Sized, A: Allocator> Box<T, A> { - /// Constructs a box from a raw pointer in the given allocator. - /// - /// After calling this function, the raw pointer is owned by the - /// resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. For this - /// to be safe, the memory must have been allocated in accordance - /// with the [memory layout] used by `Box` . - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to - /// memory problems. For example, a double-free may occur if the - /// function is called twice on the same raw pointer. - /// - /// The raw pointer must point to a block of memory allocated by `alloc`. - /// - /// # Examples - /// - /// Recreate a `Box` which was previously converted to a raw pointer - /// using [`Box::into_raw_with_allocator`]: - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::alloc::System; - /// - /// let x = Box::new_in(5, System); - /// let (ptr, alloc) = Box::into_raw_with_allocator(x); - /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; - /// ``` - /// Manually create a `Box` from scratch by using the system allocator: - /// ``` - /// #![feature(allocator_api, slice_ptr_get)] - /// - /// use std::alloc::{Allocator, Layout, System}; - /// - /// unsafe { - /// let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32; - /// // In general .write is required to avoid attempting to destruct - /// // the (uninitialized) previous contents of `ptr`, though for this - /// // simple example `*ptr = 5` would have worked as well. - /// ptr.write(5); - /// let x = Box::from_raw_in(ptr, System); - /// } - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [memory layout]: self#memory-layout - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - Box(unsafe { Unique::new_unchecked(raw) }, alloc) - } - - /// Constructs a box from a `NonNull` pointer in the given allocator. - /// - /// After calling this function, the `NonNull` pointer is owned by - /// the resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. For this - /// to be safe, the memory must have been allocated in accordance - /// with the [memory layout] used by `Box` . - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to - /// memory problems. For example, a double-free may occur if the - /// function is called twice on the same raw pointer. - /// - /// The non-null pointer must point to a block of memory allocated by `alloc`. - /// - /// # Examples - /// - /// Recreate a `Box` which was previously converted to a `NonNull` pointer - /// using [`Box::into_non_null_with_allocator`]: - /// ``` - /// #![feature(allocator_api, box_vec_non_null)] - /// - /// use std::alloc::System; - /// - /// let x = Box::new_in(5, System); - /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); - /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; - /// ``` - /// Manually create a `Box` from scratch by using the system allocator: - /// ``` - /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)] - /// - /// use std::alloc::{Allocator, Layout, System}; - /// - /// unsafe { - /// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>(); - /// // In general .write is required to avoid attempting to destruct - /// // the (uninitialized) previous contents of `non_null`. - /// non_null.write(5); - /// let x = Box::from_non_null_in(non_null, System); - /// } - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [memory layout]: self#memory-layout - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - #[inline] - pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self { - // SAFETY: guaranteed by the caller. - unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } - } /// Consumes the `Box`, returning a wrapped raw pointer. /// @@ -1259,8 +1150,11 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Self) -> *mut T { - // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here. - unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 } + // Avoid `into_raw_with_allocator` as that interacts poorly with Miri's Stacked Borrows. + let mut b = mem::ManuallyDrop::new(b); + // We go through the built-in deref for `Box`, which is crucial for Miri to recognize this + // operation for it's alias tracking. + &raw mut **b } /// Consumes the `Box`, returning a wrapped `NonNull` pointer. @@ -1322,6 +1216,115 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { // SAFETY: `Box` is guaranteed to be non-null. unsafe { NonNull::new_unchecked(Self::into_raw(b)) } } +} + +impl<T: ?Sized, A: Allocator> Box<T, A> { + /// Constructs a box from a raw pointer in the given allocator. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// The raw pointer must point to a block of memory allocated by `alloc`. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw_with_allocator`]: + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(5, System); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); + /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// #![feature(allocator_api, slice_ptr_get)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// unsafe { + /// let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32; + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); + /// let x = Box::from_raw_in(ptr, System); + /// } + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + Box(unsafe { Unique::new_unchecked(raw) }, alloc) + } + + /// Constructs a box from a `NonNull` pointer in the given allocator. + /// + /// After calling this function, the `NonNull` pointer is owned by + /// the resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// The non-null pointer must point to a block of memory allocated by `alloc`. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a `NonNull` pointer + /// using [`Box::into_non_null_with_allocator`]: + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(5, System); + /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); + /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// unsafe { + /// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>(); + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `non_null`. + /// non_null.write(5); + /// let x = Box::from_non_null_in(non_null, System); + /// } + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self { + // SAFETY: guaranteed by the caller. + unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } + } /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. /// @@ -1602,7 +1605,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { where A: 'a, { - unsafe { &mut *Box::into_raw(b) } + let (ptr, alloc) = Box::into_raw_with_allocator(b); + mem::forget(alloc); + unsafe { &mut *ptr } } /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 010d17f7476..5018ff4ad71 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1322,6 +1322,30 @@ impl<T: ?Sized> Rc<T> { unsafe { Self::from_raw_in(ptr, Global) } } + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + /// Increments the strong reference count on the `Rc<T>` associated with the /// provided pointer by one. /// @@ -1408,30 +1432,6 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { &this.alloc } - /// Consumes the `Rc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Rc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - /// Consumes the `Rc`, returning the wrapped pointer and allocator. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -1525,7 +1525,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// use std::alloc::System; /// /// let x = Rc::new_in("hello".to_owned(), System); - /// let x_ptr = Rc::into_raw(x); + /// let (x_ptr, _alloc) = Rc::into_raw_with_allocator(x); /// /// unsafe { /// // Convert back to an `Rc` to prevent leak. @@ -1547,7 +1547,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// use std::alloc::System; /// /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// let x_ptr: *const [u32] = Rc::into_raw_with_allocator(x).0; /// /// unsafe { /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); @@ -1648,7 +1648,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// let five = Rc::new_in(5, System); /// /// unsafe { - /// let ptr = Rc::into_raw(five); + /// let (ptr, _alloc) = Rc::into_raw_with_allocator(five); /// Rc::increment_strong_count_in(ptr, System); /// /// let five = Rc::from_raw_in(ptr, System); @@ -1694,7 +1694,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// let five = Rc::new_in(5, System); /// /// unsafe { - /// let ptr = Rc::into_raw(five); + /// let (ptr, _alloc) = Rc::into_raw_with_allocator(five); /// Rc::increment_strong_count_in(ptr, System); /// /// let five = Rc::from_raw_in(ptr, System); @@ -3123,6 +3123,39 @@ impl<T: ?Sized> Weak<T> { pub unsafe fn from_raw(ptr: *const T) -> Self { unsafe { Self::from_raw_in(ptr, Global) } } + + /// Consumes the `Weak<T>` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak<T>` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + mem::ManuallyDrop::new(self).as_ptr() + } } impl<T: ?Sized, A: Allocator> Weak<T, A> { @@ -3175,39 +3208,6 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> { } } - /// Consumes the `Weak<T>` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak<T>` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - mem::ManuallyDrop::new(self).as_ptr() - } - /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator. /// /// This converts the weak pointer into a raw pointer, while still preserving the ownership of diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1e3c03977bd..b8925f4544f 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1467,6 +1467,30 @@ impl<T: ?Sized> Arc<T> { unsafe { Arc::from_raw_in(ptr, Global) } } + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new("hello".to_owned()); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Arc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + /// Increments the strong reference count on the `Arc<T>` associated with the /// provided pointer by one. /// @@ -1558,30 +1582,6 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { &this.alloc } - /// Consumes the `Arc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Arc` using - /// [`Arc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new("hello".to_owned()); - /// let x_ptr = Arc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Arc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - /// Consumes the `Arc`, returning the wrapped pointer and allocator. /// /// To avoid a memory leak the pointer must be converted back to an `Arc` using @@ -1676,7 +1676,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// use std::alloc::System; /// /// let x = Arc::new_in("hello".to_owned(), System); - /// let x_ptr = Arc::into_raw(x); + /// let (x_ptr, alloc) = Arc::into_raw_with_allocator(x); /// /// unsafe { /// // Convert back to an `Arc` to prevent leak. @@ -1698,7 +1698,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// use std::alloc::System; /// /// let x: Arc<[u32], _> = Arc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Arc::into_raw(x); + /// let x_ptr: *const [u32] = Arc::into_raw_with_allocator(x).0; /// /// unsafe { /// let x: Arc<[u32; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); @@ -1850,7 +1850,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// let five = Arc::new_in(5, System); /// /// unsafe { - /// let ptr = Arc::into_raw(five); + /// let (ptr, _alloc) = Arc::into_raw_with_allocator(five); /// Arc::increment_strong_count_in(ptr, System); /// /// // This assertion is deterministic because we haven't shared @@ -1899,7 +1899,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// let five = Arc::new_in(5, System); /// /// unsafe { - /// let ptr = Arc::into_raw(five); + /// let (ptr, _alloc) = Arc::into_raw_with_allocator(five); /// Arc::increment_strong_count_in(ptr, System); /// /// // Those assertions are deterministic because we haven't shared @@ -2863,6 +2863,39 @@ impl<T: ?Sized> Weak<T> { pub unsafe fn from_raw(ptr: *const T) -> Self { unsafe { Weak::from_raw_in(ptr, Global) } } + + /// Consumes the `Weak<T>` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak<T>` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// let strong = Arc::new("hello".to_owned()); + /// let weak = Arc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Arc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Arc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + ManuallyDrop::new(self).as_ptr() + } } impl<T: ?Sized, A: Allocator> Weak<T, A> { @@ -2915,39 +2948,6 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> { } } - /// Consumes the `Weak<T>` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak<T>` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// let strong = Arc::new("hello".to_owned()); - /// let weak = Arc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Arc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Arc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - ManuallyDrop::new(self).as_ptr() - } - /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator. /// /// This converts the weak pointer into a raw pointer, while still preserving the ownership of diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 5bd82560da7..c8341750f4d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -761,6 +761,88 @@ impl<T> Vec<T> { pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { PeekMut::new(self) } + + /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: Vec::from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let v: Vec<i32> = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } + + #[doc(alias = "into_non_null_parts")] + /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`. + /// + /// Returns the `NonNull` pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the `NonNull` pointer, length, and capacity back + /// into a `Vec` with the [`from_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_parts`]: Vec::from_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts, box_vec_non_null)] + /// + /// let v: Vec<i32> = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr.cast::<u32>(); + /// + /// Vec::from_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_parts(self) -> (NonNull<T>, usize, usize) { + let (ptr, len, capacity) = self.into_raw_parts(); + // SAFETY: A `Vec` always has a non-null pointer. + (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) + } } impl<T, A: Allocator> Vec<T, A> { @@ -1095,88 +1177,6 @@ impl<T, A: Allocator> Vec<T, A> { unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } - /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`. - /// - /// Returns the raw pointer to the underlying data, the length of - /// the vector (in elements), and the allocated capacity of the - /// data (in elements). These are the same arguments in the same - /// order as the arguments to [`from_raw_parts`]. - /// - /// After calling this function, the caller is responsible for the - /// memory previously managed by the `Vec`. The only way to do - /// this is to convert the raw pointer, length, and capacity back - /// into a `Vec` with the [`from_raw_parts`] function, allowing - /// the destructor to perform the cleanup. - /// - /// [`from_raw_parts`]: Vec::from_raw_parts - /// - /// # Examples - /// - /// ``` - /// #![feature(vec_into_raw_parts)] - /// let v: Vec<i32> = vec![-1, 0, 1]; - /// - /// let (ptr, len, cap) = v.into_raw_parts(); - /// - /// let rebuilt = unsafe { - /// // We can now make changes to the components, such as - /// // transmuting the raw pointer to a compatible type. - /// let ptr = ptr as *mut u32; - /// - /// Vec::from_raw_parts(ptr, len, cap) - /// }; - /// assert_eq!(rebuilt, [4294967295, 0, 1]); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts(self) -> (*mut T, usize, usize) { - let mut me = ManuallyDrop::new(self); - (me.as_mut_ptr(), me.len(), me.capacity()) - } - - #[doc(alias = "into_non_null_parts")] - /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`. - /// - /// Returns the `NonNull` pointer to the underlying data, the length of - /// the vector (in elements), and the allocated capacity of the - /// data (in elements). These are the same arguments in the same - /// order as the arguments to [`from_parts`]. - /// - /// After calling this function, the caller is responsible for the - /// memory previously managed by the `Vec`. The only way to do - /// this is to convert the `NonNull` pointer, length, and capacity back - /// into a `Vec` with the [`from_parts`] function, allowing - /// the destructor to perform the cleanup. - /// - /// [`from_parts`]: Vec::from_parts - /// - /// # Examples - /// - /// ``` - /// #![feature(vec_into_raw_parts, box_vec_non_null)] - /// - /// let v: Vec<i32> = vec![-1, 0, 1]; - /// - /// let (ptr, len, cap) = v.into_parts(); - /// - /// let rebuilt = unsafe { - /// // We can now make changes to the components, such as - /// // transmuting the raw pointer to a compatible type. - /// let ptr = ptr.cast::<u32>(); - /// - /// Vec::from_parts(ptr, len, cap) - /// }; - /// assert_eq!(rebuilt, [4294967295, 0, 1]); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_parts(self) -> (NonNull<T>, usize, usize) { - let (ptr, len, capacity) = self.into_raw_parts(); - // SAFETY: A `Vec` always has a non-null pointer. - (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) - } - /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity, allocator)`. /// /// Returns the raw pointer to the underlying data, the length of the vector (in elements), @@ -3031,6 +3031,61 @@ impl<T, A: Allocator> Vec<T, A> { (initialized, spare, &mut self.len) } } + + /// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping + /// elements in the remainder. `N` must be greater than zero. + /// + /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the + /// nearest multiple with a reallocation or deallocation. + /// + /// This function can be used to reverse [`Vec::into_flattened`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_chunks)] + /// + /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; + /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]); + /// + /// let vec = vec![0, 1, 2, 3]; + /// let chunks: Vec<[u8; 10]> = vec.into_chunks(); + /// assert!(chunks.is_empty()); + /// + /// let flat = vec![0; 8 * 8 * 8]; + /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks(); + /// assert_eq!(reshaped.len(), 1); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "vec_into_chunks", issue = "142137")] + pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> { + const { + assert!(N != 0, "chunk size must be greater than zero"); + } + + let (len, cap) = (self.len(), self.capacity()); + + let len_remainder = len % N; + if len_remainder != 0 { + self.truncate(len - len_remainder); + } + + let cap_remainder = cap % N; + if !T::IS_ZST && cap_remainder != 0 { + self.buf.shrink_to_fit(cap - cap_remainder); + } + + let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc(); + + // SAFETY: + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `[T; N]` has the same alignment as `T` + // - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap` + // - `len / N <= cap / N` because `len <= cap` + // - the allocated memory consists of `len / N` valid values of type `[T; N]` + // - `cap / N` fits the size of the allocated memory after shrinking + unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) } + } } impl<T: Clone, A: Allocator> Vec<T, A> { diff --git a/library/core/src/error.rs b/library/core/src/error.rs index bfa392003b9..7f5c6ac42bc 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -347,7 +347,7 @@ impl dyn Error { /// let b = B(Some(Box::new(A))); /// /// // let err : Box<Error> = b.into(); // or - /// let err = &b as &(dyn Error); + /// let err = &b as &dyn Error; /// /// let mut iter = err.sources(); /// diff --git a/library/core/src/ffi/c_char.md b/library/core/src/ffi/c_char.md index b262a3663b3..119b739a39e 100644 --- a/library/core/src/ffi/c_char.md +++ b/library/core/src/ffi/c_char.md @@ -1,6 +1,6 @@ Equivalent to C's `char` type. -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addressed memory with 8-bit bytes. C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See `CStr` for more information. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 2be8d37bbee..c593737af8a 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2867,7 +2867,7 @@ macro_rules! tuple { maybe_tuple_doc! { $($name)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized { + impl<$($name:Debug),+> Debug for ($($name,)+) { #[allow(non_snake_case, unused_assignments)] fn fmt(&self, f: &mut Formatter<'_>) -> Result { let mut builder = f.debug_tuple(""); @@ -2898,11 +2898,6 @@ macro_rules! maybe_tuple_doc { }; } -macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; -} - tuple! { E, D, C, B, A, Z, Y, X, W, V, U, T, } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index efda64791d4..a10c85640bb 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -886,7 +886,7 @@ mod impls { maybe_tuple_doc! { $($name)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { + impl<$($name: Hash),+> Hash for ($($name,)+) { #[allow(non_snake_case)] #[inline] fn hash<S: Hasher>(&self, state: &mut S) { @@ -912,11 +912,6 @@ mod impls { }; } - macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; - } - impl_hash_tuple! {} impl_hash_tuple! { T } impl_hash_tuple! { T B } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 15d4f14038a..ab99492638e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -472,7 +472,8 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { } /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: -/// This will statically either panic, or do nothing. +/// This will statically either panic, or do nothing. It does not *guarantee* to ever panic, +/// and should only be called if an assertion failure will imply language UB in the following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] @@ -481,7 +482,9 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { pub const fn assert_inhabited<T>(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit -/// zero-initialization: This will statically either panic, or do nothing. +/// zero-initialization: This will statically either panic, or do nothing. It does not *guarantee* +/// to ever panic, and should only be called if an assertion failure will imply language UB in the +/// following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] @@ -489,7 +492,9 @@ pub const fn assert_inhabited<T>(); #[rustc_intrinsic] pub const fn assert_zero_valid<T>(); -/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. +/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. It does +/// not *guarantee* to ever panic, and should only be called if an assertion failure will imply +/// language UB in the following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 63a479ed8dd..fc35e54bb0d 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -616,7 +616,9 @@ impl<T> MaybeUninit<T> { // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::<T>(); - ManuallyDrop::into_inner(self.value) + // We do this via a raw ptr read instead of `ManuallyDrop::into_inner` so that there's + // no trace of `ManuallyDrop` in Miri's error messages here. + (&raw const self.value).cast::<T>().read() } } diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 6ef2fdd14c1..a5242d60bf1 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -79,7 +79,7 @@ pub struct ParseIntError { /// # } /// ``` #[stable(feature = "int_error_matching", since = "1.55.0")] -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] #[non_exhaustive] pub enum IntErrorKind { /// Value being parsed is empty. diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 1935268cda8..ad3b6439a61 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1211,7 +1211,7 @@ pub enum OneSidedRangeBound { /// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded` /// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. #[unstable(feature = "one_sided_range", issue = "69780")] -pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> { +pub trait OneSidedRange<T>: RangeBounds<T> { /// An internal-only helper function for `split_off` and /// `split_off_mut` that returns the bound of the one-sided range. fn bound(self) -> (OneSidedRangeBound, T); diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 6327c41f052..9cf08e74ff6 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,7 +1,7 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; -use crate::marker::{ConstParamTy_, PointeeSized, StructuralPartialEq, UnsizedConstParamTy}; +use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; use crate::ops::ControlFlow::{self, Break, Continue}; use crate::random::{Random, RandomSource}; @@ -24,10 +24,7 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: PartialEq),+> PartialEq for ($($T,)+) - where - last_type!($($T,)+): PointeeSized - { + impl<$($T: PartialEq),+> PartialEq for ($($T,)+) { #[inline] fn eq(&self, other: &($($T,)+)) -> bool { $( ${ignore($T)} self.${index()} == other.${index()} )&&+ @@ -43,8 +40,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: Eq),+> Eq for ($($T,)+) - where - last_type!($($T,)+): PointeeSized {} } @@ -73,8 +68,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+) - where - last_type!($($T,)+): PointeeSized { #[inline] fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> { @@ -119,8 +112,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: Ord),+> Ord for ($($T,)+) - where - last_type!($($T,)+): PointeeSized { #[inline] fn cmp(&self, other: &($($T,)+)) -> Ordering { @@ -245,9 +236,4 @@ macro_rules! lexical_cmp { ($a:expr, $b:expr) => { ($a).cmp(&$b) }; } -macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; -} - tuple_impls!(E D C B A Z Y X W V U T); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 7ae8e700ff6..72ad7c244ee 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -4,6 +4,27 @@ //! filesystem. All methods in this module represent cross-platform filesystem //! operations. Extra platform-specific functionality can be found in the //! extension traits of `std::os::$platform`. +//! +//! # Time of Check to Time of Use (TOCTOU) +//! +//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use" +//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions) +//! and then uses the result of that check to make a decision, but the condition may have changed +//! between the check and the use. +//! +//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to +//! TOCTOU - another process could create the file between your check and creation attempt. +//! +//! Another example is with symbolic links: when removing a directory, if another process replaces +//! the directory with a symbolic link between the check and the removal operation, the removal +//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use +//! atomic operations to prevent such race conditions. +//! +//! To avoid TOCTOU issues: +//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by +//! changes made by other processes. +//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating). +//! - Keep file open for the duration of operations. #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] @@ -548,13 +569,14 @@ impl File { /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking whether a file - /// exists and creating a new one, the file may have been created by another process (a TOCTOU + /// exists and creating a new one, the file may have been created by another process (a [TOCTOU] /// race condition / attack). /// /// This can also be written using /// `File::options().read(true).write(true).create_new(true).open(...)`. /// /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -1610,7 +1632,7 @@ impl OpenOptions { /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been - /// created by another process (a TOCTOU race condition / attack). + /// created by another process (a [TOCTOU] race condition / attack). /// /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are /// ignored. @@ -1621,6 +1643,7 @@ impl OpenOptions { /// [`.create()`]: OpenOptions::create /// [`.truncate()`]: OpenOptions::truncate /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -2954,17 +2977,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. /// /// ## Time-of-check to time-of-use (TOCTOU) race conditions -/// On a few platforms there is no way to remove a directory's contents without following symlinks -/// unless you perform a check and then operate on paths based on that directory. -/// This allows concurrently-running code to replace the directory with a symlink after the check, -/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race. -/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms -/// except the following. It should not be used in security-sensitive contexts on these platforms: -/// - Miri: Even when emulating targets where the underlying implementation will protect against -/// TOCTOU races, Miri will not do so. -/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement -/// the required platform support to do so. +/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou). +/// +/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default. +/// However, on the following platforms, this protection is not provided and the function should +/// not be used in security-sensitive contexts: +/// - **Miri**: Even when emulating targets where the underlying implementation will protect against +/// TOCTOU races, Miri will not do so. +/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement +/// the required platform support to do so. /// +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// [changes]: io#platform-specific-behavior /// /// # Errors @@ -3238,7 +3261,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not -/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios +/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// # Examples @@ -3251,6 +3274,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { /// ``` /// /// [`Path::exists`]: crate::path::Path::exists +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou #[stable(feature = "fs_try_exists", since = "1.81.0")] #[inline] pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index b734d2b324c..0ce20a143df 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3127,7 +3127,7 @@ impl Path { /// Returns `true` if the path points at an existing entity. /// /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! - /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs. + /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -3148,6 +3148,7 @@ impl Path { /// check errors, call [`Path::try_exists`]. /// /// [`try_exists()`]: Self::try_exists + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou #[stable(feature = "path_ext", since = "1.5.0")] #[must_use] #[inline] @@ -3167,7 +3168,7 @@ impl Path { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not - /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios + /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// This is an alias for [`std::fs::exists`](crate::fs::exists). @@ -3180,6 +3181,7 @@ impl Path { /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); /// ``` /// + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou /// [`exists()`]: Self::exists #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 567416d079b..6c5f70b2f43 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -5,7 +5,7 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo}; use crate::core::builder::{ - self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description, + self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; use crate::core::config::TargetSelection; use crate::utils::build_stamp::{self, BuildStamp}; @@ -167,6 +167,10 @@ impl Step for Std { let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage)); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check("std", self.target)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -258,6 +262,10 @@ impl Step for Rustc { let hostdir = builder.sysroot_target_libdir(compiler, compiler.host); add_to_sysroot(builder, &libdir, &hostdir, &stamp); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check("rustc", self.target)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -315,6 +323,10 @@ impl Step for CodegenBackend { run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check(self.backend, self.target)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -373,6 +385,10 @@ impl Step for RustAnalyzer { let _guard = builder.msg_check("rust-analyzer artifacts", target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check("rust-analyzer", self.target)) + } } /// Compiletest is implicitly "checked" when it gets built in order to run tests, @@ -432,6 +448,10 @@ impl Step for Compiletest { let _guard = builder.msg_check("compiletest artifacts", self.target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check("compiletest", self.target)) + } } macro_rules! tool_check_step { @@ -467,6 +487,10 @@ macro_rules! tool_check_step { let Self { target } = self; run_tool_check_step(builder, target, stringify!($name), $path); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check(stringify!($name), self.target)) + } } } } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 84064150738..c3a3eddd161 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -306,11 +306,7 @@ impl Step for Std { } fn metadata(&self) -> Option<StepMetadata> { - Some( - StepMetadata::build("std", self.target) - .built_by(self.compiler) - .stage(self.compiler.stage), - ) + Some(StepMetadata::build("std", self.target).built_by(self.compiler)) } } @@ -1186,11 +1182,7 @@ impl Step for Rustc { } fn metadata(&self) -> Option<StepMetadata> { - Some( - StepMetadata::build("rustc", self.target) - .built_by(self.build_compiler) - .stage(self.build_compiler.stage + 1), - ) + Some(StepMetadata::build("rustc", self.target).built_by(self.build_compiler)) } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 01b181f55de..2d4d9e53598 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1108,7 +1108,9 @@ impl Step for Tidy { if builder.config.cmd.bless() { cmd.arg("--bless"); } - if let Some(s) = builder.config.cmd.extra_checks() { + if let Some(s) = + builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref()) + { cmd.arg(format!("--extra-checks={s}")); } let mut args = std::env::args_os(); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index a7220515ca0..ad3f8d89767 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1195,7 +1195,6 @@ macro_rules! tool_extended { Some( StepMetadata::build($tool_name, self.target) .built_by(self.compiler.with_stage(self.compiler.stage.saturating_sub(1))) - .stage(self.compiler.stage) ) } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8e9e8b496de..b96a988cde3 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -153,6 +153,10 @@ impl StepMetadata { Self::new(name, target, Kind::Build) } + pub fn check(name: &'static str, target: TargetSelection) -> Self { + Self::new(name, target, Kind::Check) + } + pub fn doc(name: &'static str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Doc) } @@ -178,6 +182,14 @@ impl StepMetadata { self.stage = Some(stage); self } + + pub fn get_stage(&self) -> Option<u32> { + self.stage.or(self + .built_by + // For std, its stage corresponds to the stage of the compiler that builds it. + // For everything else, a stage N things gets built by a stage N-1 compiler. + .map(|compiler| if self.name == "std" { compiler.stage } else { compiler.stage + 1 })) + } } pub struct RunConfig<'a> { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 8adf93ea528..1c5267cb75e 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -863,7 +863,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("build") .path("opt-dist") - .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -880,7 +880,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(1) - .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -890,7 +890,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(2) - .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -984,8 +984,8 @@ mod snapshot { ctx .config("dist") .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -993,14 +993,14 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [dist] src <> " ); @@ -1014,25 +1014,25 @@ mod snapshot { .config("dist") .args(&["--set", "build.extended=true"]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> - [build] rustc 0 <host> -> WasmComponentLd <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> [build] rustc 1 <host> -> std 1 <host> [build] rustc 1 <host> -> rustc 2 <host> - [build] rustc 1 <host> -> WasmComponentLd <host> + [build] rustc 1 <host> -> WasmComponentLd 2 <host> [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [dist] src <> [build] rustc 0 <host> -> rustfmt 1 <host> [build] rustc 0 <host> -> cargo-fmt 1 <host> @@ -1052,8 +1052,8 @@ mod snapshot { .hosts(&[&host_target()]) .targets(&[&host_target(), TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1062,19 +1062,19 @@ mod snapshot { [doc] std 2 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [dist] docs <target1> [doc] std 2 <host> [doc] std 2 <target1> [dist] mingw <host> [dist] mingw <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [build] rustc 2 <host> -> std 2 <target1> - [dist] rustc 2 <host> -> std <target1> + [dist] rustc 2 <host> -> std 2 <target1> [dist] src <> " ); @@ -1089,8 +1089,8 @@ mod snapshot { .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target()]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1098,20 +1098,20 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> + [build] rustc 0 <host> -> LintDocs 1 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> [build] rustdoc 1 <target1> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [dist] src <> " ); @@ -1126,8 +1126,8 @@ mod snapshot { .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target(), TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1136,24 +1136,24 @@ mod snapshot { [doc] std 2 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> + [build] rustc 0 <host> -> LintDocs 1 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [dist] docs <target1> [doc] std 2 <host> [doc] std 2 <target1> [dist] mingw <host> [dist] mingw <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> [build] rustdoc 1 <target1> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <host> - [dist] rustc 1 <host> -> std <target1> + [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> std 1 <target1> [dist] src <> " ); @@ -1168,8 +1168,8 @@ mod snapshot { .hosts(&[]) .targets(&[TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1177,12 +1177,12 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <target1> [doc] std 2 <target1> [dist] mingw <target1> [build] rustc 2 <host> -> std 2 <target1> - [dist] rustc 2 <host> -> std <target1> + [dist] rustc 2 <host> -> std 2 <target1> "); } @@ -1198,31 +1198,31 @@ mod snapshot { .targets(&[TEST_TRIPLE_1]) .args(&["--set", "rust.channel=nightly", "--set", "build.extended=true"]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> - [build] rustc 0 <host> -> WasmComponentLd <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> [build] rustc 1 <host> -> std 1 <host> [build] rustc 1 <host> -> rustc 2 <host> - [build] rustc 1 <host> -> WasmComponentLd <host> + [build] rustc 1 <host> -> WasmComponentLd 2 <host> [build] rustdoc 1 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <target1> [doc] std 2 <target1> [dist] mingw <target1> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> - [build] rustc 1 <host> -> WasmComponentLd <target1> + [build] rustc 1 <host> -> WasmComponentLd 2 <target1> [build] rustdoc 1 <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <target1> + [dist] rustc 1 <host> -> std 1 <target1> [dist] src <> [build] rustc 0 <host> -> rustfmt 1 <target1> [build] rustc 0 <host> -> cargo-fmt 1 <target1> @@ -1234,6 +1234,289 @@ mod snapshot { } #[test] + fn check_compiler_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] cranelift <host> + [check] gcc <host> + "); + + insta::assert_snapshot!( + ctx.config("check") + .path("rustc") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + "); + } + + #[test] + fn check_compiler_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("compiler").stage(0).run(); + } + + #[test] + fn check_compiler_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .stage(1) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] rustc <host> + [check] cranelift <host> + [check] gcc <host> + "); + } + + #[test] + fn check_compiler_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 2 <host> -> std 2 <host> + [check] rustc <host> + [check] cranelift <host> + [check] gcc <host> + "); + } + + #[test] + fn check_cross_compile() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .stage(2) + .targets(&[TEST_TRIPLE_1]) + .hosts(&[TEST_TRIPLE_1]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 2 <host> -> std 2 <host> + [build] rustc 1 <host> -> std 1 <target1> + [build] rustc 2 <host> -> std 2 <target1> + [check] rustc <target1> + [check] Rustdoc <target1> + [check] cranelift <target1> + [check] gcc <target1> + [check] Clippy <target1> + [check] Miri <target1> + [check] CargoMiri <target1> + [check] MiroptTestTools <target1> + [check] Rustfmt <target1> + [check] rust-analyzer <target1> + [check] TestFloatParse <target1> + [check] FeaturesStatusDump <target1> + [check] std <target1> + "); + } + + #[test] + fn check_library_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] std <host> + "); + } + + #[test] + fn check_library_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("library").stage(0).run(); + } + + #[test] + fn check_library_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .stage(1) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] std <host> + "); + } + + #[test] + fn check_library_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [check] std <host> + "); + } + + #[test] + fn check_library_cross_compile() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .paths(&["core", "alloc", "std"]) + .targets(&[TEST_TRIPLE_1, TEST_TRIPLE_2]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] std <target1> + [check] std <target2> + "); + } + + #[test] + fn check_miri_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] Miri <host> + "); + } + + #[test] + fn check_miri_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("miri").stage(0).run(); + } + + #[test] + fn check_miri_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .stage(1) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] rustc <host> + [check] Miri <host> + "); + } + + #[test] + fn check_miri_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 2 <host> -> std 2 <host> + [check] rustc <host> + [check] Miri <host> + "); + } + + #[test] + fn check_compiletest() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiletest") + .render_steps(), @"[check] compiletest <host>"); + } + + #[test] + fn check_compiletest_stage1_libtest() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiletest") + .args(&["--set", "build.compiletest-use-stage0-libtest=false"]) + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] compiletest <host> + "); + } + + #[test] + fn check_codegen() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rustc_codegen_cranelift") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] cranelift <host> + [check] gcc <host> + "); + } + + #[test] + fn check_rust_analyzer() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rust-analyzer") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] rust-analyzer <host> + "); + } + + #[test] + fn check_bootstrap_tool() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("run-make-support") + .render_steps(), @r" + [check] std <host> + [build] llvm <host> + [check] rustc <host> + [check] RunMakeSupport <host> + "); + } + + #[test] fn test_exclude() { let ctx = TestCtx::new(); let steps = ctx.config("test").args(&["--skip", "src/tools/tidy"]).get_steps(); @@ -1384,7 +1667,7 @@ fn render_metadata(metadata: &StepMetadata) -> String { if let Some(compiler) = metadata.built_by { write!(record, "{} -> ", render_compiler(compiler)); } - let stage = if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() }; + let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default(); write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target)); record } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0cdfbbdaf75..49b3fec4c35 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -297,7 +297,8 @@ pub struct Config { /// Whether to use the precompiled stage0 libtest with compiletest. pub compiletest_use_stage0_libtest: bool, - + /// Default value for `--extra-checks` + pub tidy_extra_checks: Option<String>, pub is_running_on_ci: bool, /// Cache for determining path modifications @@ -744,6 +745,7 @@ impl Config { jobs, compiletest_diff_tool, compiletest_use_stage0_libtest, + tidy_extra_checks, mut ccache, exclude, } = toml.build.unwrap_or_default(); @@ -1010,6 +1012,7 @@ impl Config { optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true); + config.tidy_extra_checks = tidy_extra_checks; let download_rustc = config.download_rustc_commit.is_some(); config.explicit_stage_from_cli = flags_stage.is_some(); diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 98e1194de72..4d29691f38b 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -69,6 +69,7 @@ define_config! { jobs: Option<u32> = "jobs", compiletest_diff_tool: Option<String> = "compiletest-diff-tool", compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest", + tidy_extra_checks: Option<String> = "tidy-extra-checks", ccache: Option<StringOrBool> = "ccache", exclude: Option<Vec<PathBuf>> = "exclude", } diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 642f2f2271d..ac5eaea3bcb 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -393,6 +393,27 @@ pub fn check_incompatible_options_for_ci_rustc( Ok(()) } +pub(crate) const VALID_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"]; + +pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) -> Vec<String> { + for backend in &backends { + if let Some(stripped) = backend.strip_prefix(CODEGEN_BACKEND_PREFIX) { + panic!( + "Invalid value '{backend}' for '{section}.codegen-backends'. \ + Codegen backends are defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + Please, use '{stripped}' instead." + ) + } + if !VALID_CODEGEN_BACKENDS.contains(&backend.as_str()) { + println!( + "HELP: '{backend}' for '{section}.codegen-backends' might fail. \ + List of known good values: {VALID_CODEGEN_BACKENDS:?}" + ); + } + } + backends +} + impl Config { pub fn apply_rust_config( &mut self, @@ -571,24 +592,10 @@ impl Config { set(&mut self.ehcont_guard, ehcont_guard); self.llvm_libunwind_default = llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - - if let Some(ref backends) = codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - self.rust_codegen_backends = backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect(); - } + set( + &mut self.rust_codegen_backends, + codegen_backends.map(|backends| validate_codegen_backends(backends, "rust")), + ); self.rust_codegen_units = codegen_units.map(threads_from_config); self.rust_codegen_units_std = codegen_units_std.map(threads_from_config); diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index b9f6780ca3f..337276948b3 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use serde::{Deserialize, Deserializer}; -use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::toml::rust::validate_codegen_backends; use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit}; @@ -142,23 +142,9 @@ impl Config { target.rpath = cfg.rpath; target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; target.jemalloc = cfg.jemalloc; - - if let Some(ref backends) = cfg.codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - target.codegen_backends = Some(backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect()); + if let Some(backends) = cfg.codegen_backends { + target.codegen_backends = + Some(validate_codegen_backends(backends, &format!("target.{triple}"))) } target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs index 8562a35b3e0..fd0a7cccd60 100644 --- a/src/bootstrap/src/utils/cache/tests.rs +++ b/src/bootstrap/src/utils/cache/tests.rs @@ -1,12 +1,13 @@ use std::path::PathBuf; -use crate::utils::cache::{INTERNER, Internable, TyIntern}; +use crate::utils::cache::{INTERNER, Internable, Interner, TyIntern}; #[test] fn test_string_interning() { - let s1 = INTERNER.intern_str("Hello"); - let s2 = INTERNER.intern_str("Hello"); - let s3 = INTERNER.intern_str("world"); + let interner = Interner::default(); + let s1 = interner.intern_str("Hello"); + let s2 = interner.intern_str("Hello"); + let s3 = interner.intern_str("world"); assert_eq!(s1, s2, "Same strings should be interned to the same instance"); assert_ne!(s1, s3, "Different strings should have different interned values"); @@ -14,6 +15,8 @@ fn test_string_interning() { #[test] fn test_interned_equality() { + // Because we compare with &str, and the Deref impl accesses the global + // INTERNER variable, we cannot use a local Interner variable here. let s1 = INTERNER.intern_str("test"); let s2 = INTERNER.intern_str("test"); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index b208ae5249d..68312a503ee 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -441,4 +441,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "`llvm.lld` is no longer enabled by default for the dist profile.", }, + ChangeInfo { + change_id: 143251, + severity: ChangeSeverity::Info, + summary: "Added new option `build.tidy-extra-checks` to specify a default value for the --extra-checks cli flag.", + }, ]; diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 81e002edb15..410274227e4 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -13,7 +13,7 @@ use crate::utils::load_env_var; #[derive(serde::Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct Job { - /// Name of the job, e.g. mingw-check-1 + /// Name of the job, e.g. pr-check-1 pub name: String, /// GitHub runner on which the job should be executed pub os: String, @@ -66,6 +66,8 @@ pub struct JobDatabase { pub try_jobs: Vec<Job>, #[serde(rename = "auto")] pub auto_jobs: Vec<Job>, + #[serde(rename = "optional")] + pub optional_jobs: Vec<Job>, /// Shared environments for the individual run types. envs: JobEnvironments, @@ -75,9 +77,10 @@ impl JobDatabase { /// Find `auto` jobs that correspond to the passed `pattern`. /// Patterns are matched using the glob syntax. /// For example `dist-*` matches all jobs starting with `dist-`. - fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> { + fn find_auto_or_optional_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> { self.auto_jobs .iter() + .chain(self.optional_jobs.iter()) .filter(|j| glob_match::glob_match(pattern, &j.name)) .cloned() .collect() @@ -181,7 +184,7 @@ fn calculate_jobs( let mut jobs: Vec<Job> = vec![]; let mut unknown_patterns = vec![]; for pattern in patterns { - let matched_jobs = db.find_auto_jobs_by_pattern(pattern); + let matched_jobs = db.find_auto_or_optional_jobs_by_pattern(pattern); if matched_jobs.is_empty() { unknown_patterns.push(pattern.clone()); } else { diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs index ed5444d4333..63ac508b632 100644 --- a/src/ci/citool/src/jobs/tests.rs +++ b/src/ci/citool/src/jobs/tests.rs @@ -46,6 +46,13 @@ auto: - name: test-msvc-i686-2 os: ubuntu env: {} +optional: + - name: optional-job-1 + os: ubuntu + env: {} + - name: optional-dist-x86_64 + os: ubuntu + env: {} "#, ) .unwrap(); @@ -57,12 +64,18 @@ auto: "*i686*", &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"], ); + // Test that optional jobs are found + check_pattern(&db, "optional-*", &["optional-job-1", "optional-dist-x86_64"]); + check_pattern(&db, "*optional*", &["optional-job-1", "optional-dist-x86_64"]); } #[track_caller] fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) { - let jobs = - db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::<Vec<_>>(); + let jobs = db + .find_auto_or_optional_jobs_by_pattern(pattern) + .into_iter() + .map(|j| j.name) + .collect::<Vec<_>>(); assert_eq!(jobs, expected); } @@ -116,8 +129,13 @@ fn validate_jobs() { load_job_db(&db_str).expect("Failed to load job database") }; - let all_jobs = - db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::<Vec<_>>(); + let all_jobs = db + .pr_jobs + .iter() + .chain(db.try_jobs.iter()) + .chain(db.auto_jobs.iter()) + .chain(db.optional_jobs.iter()) + .collect::<Vec<_>>(); let errors: Vec<anyhow::Error> = all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect(); diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs index 83f2fc0ed1f..dbaf13d4f42 100644 --- a/src/ci/citool/tests/jobs.rs +++ b/src/ci/citool/tests/jobs.rs @@ -40,7 +40,7 @@ try-job: dist-i686-msvc"#, fn pr_jobs() { let stdout = get_matrix("pull_request", "commit", "refs/heads/pr/1234"); insta::assert_snapshot!(stdout, @r#" - jobs=[{"name":"mingw-check-1","full_name":"PR - mingw-check-1","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-2","full_name":"PR - mingw-check-2","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-tidy","full_name":"PR - mingw-check-tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}] + jobs=[{"name":"pr-check-1","full_name":"PR - pr-check-1","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"pr-check-2","full_name":"PR - pr-check-2","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"tidy","full_name":"PR - tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}] run_type=pr "#); } diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index d262da11102..d82b3e7648e 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -64,11 +64,11 @@ envs: # These jobs automatically inherit envs.pr, to avoid repeating # it in each job definition. pr: - - name: mingw-check-1 + - name: pr-check-1 <<: *job-linux-4c - - name: mingw-check-2 + - name: pr-check-2 <<: *job-linux-4c - - name: mingw-check-tidy + - name: tidy continue_on_error: true doc_url: https://foo.bar <<: *job-linux-4c @@ -139,3 +139,8 @@ auto: DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows + +# Jobs that only run when explicitly invoked via `@bors try`. +optional: + - name: test-optional-job + <<: *job-linux-4c diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index d5027589e0b..e6133fce83e 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -26,6 +26,5 @@ ENV RUST_CONFIGURE_ARGS \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs -# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733 ENV SCRIPT python3 ../x.py --stage 2 test && \ - python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\" + python3 ../x.py --stage 2 test src/tools/cargo diff --git a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile deleted file mode 100644 index c46a2471e75..00000000000 --- a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -FROM ubuntu:22.04 - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python3 \ - python3-pip \ - python3-pkg-resources \ - git \ - cmake \ - sudo \ - gdb \ - xz-utils \ - libssl-dev \ - pkg-config \ - mingw-w64 \ - && rm -rf /var/lib/apt/lists/* - -ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3" - -COPY scripts/nodejs.sh /scripts/ -RUN sh /scripts/nodejs.sh /node -ENV PATH="/node/bin:${PATH}" - -# Install es-check -# Pin its version to prevent unrelated CI failures due to future es-check versions. -RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/ -RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt - -COPY host-x86_64/mingw-check-1/check-default-config-profiles.sh /scripts/ -COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ - -# 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 \ - /scripts/check-default-config-profiles.sh && \ - python3 ../x.py build --stage 1 src/tools/build-manifest && \ - python3 ../x.py test --stage 0 src/tools/compiletest && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ - python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ - python3 ../x.py check --stage 1 --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 && \ - /scripts/validate-toolstate.sh && \ - reuse --include-submodules lint && \ - python3 ../x.py test collect-license-metadata && \ - # Runs checks to ensure that there are no issues in our JS code. - es-check es2019 ../src/librustdoc/html/static/js/*.js && \ - tsc --project ../src/librustdoc/html/static/js/tsconfig.json diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile new file mode 100644 index 00000000000..7a8056b70dc --- /dev/null +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -0,0 +1,58 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + python3-pip \ + python3-pkg-resources \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + libssl-dev \ + pkg-config \ + mingw-w64 \ + && rm -rf /var/lib/apt/lists/* + +ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3" + +COPY scripts/nodejs.sh /scripts/ +RUN sh /scripts/nodejs.sh /node +ENV PATH="/node/bin:${PATH}" + +# Install es-check +# Pin its version to prevent unrelated CI failures due to future es-check versions. +RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +COPY host-x86_64/pr-check-1/reuse-requirements.txt /tmp/ +RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt + +COPY host-x86_64/pr-check-1/check-default-config-profiles.sh /scripts/ +COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ + +# 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 \ + /scripts/check-default-config-profiles.sh && \ + python3 ../x.py build --stage 1 src/tools/build-manifest && \ + python3 ../x.py test --stage 0 src/tools/compiletest && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ + python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ + python3 ../x.py check --stage 1 --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 && \ + /scripts/validate-toolstate.sh && \ + reuse --include-submodules lint && \ + python3 ../x.py test collect-license-metadata && \ + # Runs checks to ensure that there are no issues in our JS code. + es-check es2019 ../src/librustdoc/html/static/js/*.js && \ + tsc --project ../src/librustdoc/html/static/js/tsconfig.json diff --git a/src/ci/docker/host-x86_64/mingw-check-1/check-default-config-profiles.sh b/src/ci/docker/host-x86_64/pr-check-1/check-default-config-profiles.sh index 0c85d4b449d..0c85d4b449d 100755 --- a/src/ci/docker/host-x86_64/mingw-check-1/check-default-config-profiles.sh +++ b/src/ci/docker/host-x86_64/pr-check-1/check-default-config-profiles.sh diff --git a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.in b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.in index d7c2d3fde5b..d7c2d3fde5b 100644 --- a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.in +++ b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.in diff --git a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.txt b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.txt index 8784e18864b..8784e18864b 100644 --- a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.txt +++ b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.txt diff --git a/src/ci/docker/host-x86_64/mingw-check-1/validate-toolstate.sh b/src/ci/docker/host-x86_64/pr-check-1/validate-toolstate.sh index a5691da8cda..a5691da8cda 100755 --- a/src/ci/docker/host-x86_64/mingw-check-1/validate-toolstate.sh +++ b/src/ci/docker/host-x86_64/pr-check-1/validate-toolstate.sh diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile index ce18a181d31..ce18a181d31 100644 --- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index 62cd8a31212..dbb950cbe0c 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -1,5 +1,5 @@ # We use the ghcr base image because ghcr doesn't have a rate limit -# and the mingw-check-tidy job doesn't cache docker images in CI. +# and the tidy job doesn't cache docker images in CI. FROM ghcr.io/rust-lang/ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive @@ -29,20 +29,20 @@ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" # Install eslint -COPY host-x86_64/mingw-check-tidy/eslint.version /tmp/ +COPY host-x86_64/tidy/eslint.version /tmp/ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/ +COPY host-x86_64/pr-check-1/reuse-requirements.txt /tmp/ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt \ - && pip3 install virtualenv + && pip3 install virtualenv -COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ +COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ - src/tools/tidy tidyselftest --extra-checks=py,cpp + src/tools/tidy tidyselftest --extra-checks=py,cpp diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/eslint.version b/src/ci/docker/host-x86_64/tidy/eslint.version index 1acea15afd6..1acea15afd6 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/eslint.version +++ b/src/ci/docker/host-x86_64/tidy/eslint.version diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 3aa435003d3..01993ad28aa 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -122,11 +122,11 @@ jobs: # These jobs automatically inherit envs.pr, to avoid repeating # it in each job definition. pr: - - name: mingw-check-1 + - name: pr-check-1 <<: *job-linux-4c - - name: mingw-check-2 + - name: pr-check-2 <<: *job-linux-4c - - name: mingw-check-tidy + - name: tidy continue_on_error: true free_disk: false env: @@ -160,6 +160,17 @@ pr: try: - <<: *job-dist-x86_64-linux +# Jobs that only run when explicitly invoked in one of the following ways: +# - comment `@bors2 try jobs=<job-name>` +# - `try-job: <job-name>` in the PR description and comment `@bors try` or `@bors2 try`. +optional: + # This job is used just to test optional jobs. + # It will be replaced by tier 2 and tier 3 jobs in the future. + - name: optional-mingw-check-1 + env: + IMAGE: mingw-check-1 + <<: *job-linux-4c + # 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. @@ -312,13 +323,13 @@ auto: /scripts/stage_2_test_set2.sh <<: *job-linux-4c - - name: mingw-check-1 + - name: pr-check-1 <<: *job-linux-4c - - name: mingw-check-2 + - name: pr-check-2 <<: *job-linux-4c - - name: mingw-check-tidy + - name: tidy free_disk: false <<: *job-linux-4c diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 96e4edc17a5..eba101a1398 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -66,8 +66,8 @@ kinds of builds (sets of jobs). ### Pull Request builds After each push to a pull request, a set of `pr` jobs are executed. Currently, -these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `mingw-check-1`, `mingw-check-2` -and `mingw-check-tidy` jobs, all running on Linux. These execute a relatively short +these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-check-2` +and `tidy` jobs, all running on Linux. These execute a relatively short (~40 minutes) and lightweight test suite that should catch common issues. More specifically, they run a set of lints, they try to perform a cross-compile check build to Windows mingw (without producing any artifacts) and they test the diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7be83b65fbf..99b3da8b2cd 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -8,6 +8,8 @@ 3. Copy the filenames with updated suffixes from the directory. */ +/* ignore-tidy-filelength */ + :root { --nav-sub-mobile-padding: 8px; --search-typename-width: 6.75rem; @@ -915,32 +917,30 @@ ul.block, .block li, .block ul { overflow: auto; } -.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] { - width: calc(1ch + var(--line-number-padding) * 2); -} -.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] { - width: calc(2ch + var(--line-number-padding) * 2); -} -.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] { - width: calc(3ch + var(--line-number-padding) * 2); -} -.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] { - width: calc(4ch + var(--line-number-padding) * 2); -} -.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] { - width: calc(5ch + var(--line-number-padding) * 2); -} -.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] { - width: calc(6ch + var(--line-number-padding) * 2); +.example-wrap code { + position: relative; } -.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] { - width: calc(7ch + var(--line-number-padding) * 2); +.example-wrap pre code span { + display: inline; } -.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] { - width: calc(8ch + var(--line-number-padding) * 2); + +.example-wrap.digits-1 { --example-wrap-digits-count: 1ch; } +.example-wrap.digits-2 { --example-wrap-digits-count: 2ch; } +.example-wrap.digits-3 { --example-wrap-digits-count: 3ch; } +.example-wrap.digits-4 { --example-wrap-digits-count: 4ch; } +.example-wrap.digits-5 { --example-wrap-digits-count: 5ch; } +.example-wrap.digits-6 { --example-wrap-digits-count: 6ch; } +.example-wrap.digits-7 { --example-wrap-digits-count: 7ch; } +.example-wrap.digits-8 { --example-wrap-digits-count: 8ch; } +.example-wrap.digits-9 { --example-wrap-digits-count: 9ch; } + +.example-wrap [data-nosnippet] { + width: calc(var(--example-wrap-digits-count) + var(--line-number-padding) * 2); } -.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] { - width: calc(9ch + var(--line-number-padding) * 2); +.example-wrap pre > code { + padding-left: calc( + var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + + var(--line-number-right-margin)); } .example-wrap [data-nosnippet] { @@ -953,63 +953,25 @@ ul.block, .block li, .block ul { -ms-user-select: none; user-select: none; padding: 0 var(--line-number-padding); -} -.example-wrap [data-nosnippet]:target { - border-right: none; + position: absolute; + left: 0; } .example-wrap .line-highlighted[data-nosnippet] { background-color: var(--src-line-number-highlighted-background-color); } -:root.word-wrap-source-code .example-wrap [data-nosnippet] { - position: absolute; - left: 0; -} -.word-wrap-source-code .example-wrap pre > code { +.example-wrap pre > code { position: relative; - word-break: break-all; + display: block; } :root.word-wrap-source-code .example-wrap pre > code { - display: block; + word-break: break-all; white-space: pre-wrap; } :root.word-wrap-source-code .example-wrap pre > code * { word-break: break-all; } -:root.word-wrap-source-code .example-wrap.digits-1 pre > code { - padding-left: calc( - 1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-2 pre > code { - padding-left: calc( - 2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-3 pre > code { - padding-left: calc( - 3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-4 pre > code { - padding-left: calc( - 4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-5 pre > code { - padding-left: calc( - 5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-6 pre > code { - padding-left: calc( - 6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-7 pre > code { - padding-left: calc( - 7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-8 pre > code { - padding-left: calc( - 8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); -} -:root.word-wrap-source-code .example-wrap.digits-9 pre > code { - padding-left: calc( - 9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +.example-wrap [data-nosnippet]:target { + border-right: none; } .example-wrap.hide-lines [data-nosnippet] { display: none; diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index dc240dd067b..8453165818b 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -98,6 +98,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { /// 17 | std::mem::forget(seven); /// | ^^^^^^^^^^^^^^^^^^^^^^^ /// ``` +#[track_caller] pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) { #[expect(clippy::disallowed_methods)] cx.span_lint(lint, sp, |diag| { @@ -143,6 +144,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult /// | /// = help: consider using `f64::NAN` if you would like a constant representing NaN /// ``` +#[track_caller] pub fn span_lint_and_help<T: LintContext>( cx: &T, lint: &'static Lint, @@ -203,6 +205,7 @@ pub fn span_lint_and_help<T: LintContext>( /// 10 | forget(&SomeStruct); /// | ^^^^^^^^^^^ /// ``` +#[track_caller] pub fn span_lint_and_note<T: LintContext>( cx: &T, lint: &'static Lint, @@ -244,6 +247,7 @@ pub fn span_lint_and_note<T: LintContext>( /// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. +#[track_caller] pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F) where C: LintContext, @@ -286,6 +290,7 @@ where /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let /// the compiler check lint level attributes at the place of the expression and /// the `#[allow]` will work. +#[track_caller] pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) { #[expect(clippy::disallowed_methods)] cx.tcx.node_span_lint(lint, hir_id, sp, |diag| { @@ -321,6 +326,7 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let /// the compiler check lint level attributes at the place of the expression and /// the `#[allow]` will work. +#[track_caller] pub fn span_lint_hir_and_then( cx: &LateContext<'_>, lint: &'static Lint, @@ -374,6 +380,7 @@ pub fn span_lint_hir_and_then( /// = note: `-D fold-any` implied by `-D warnings` /// ``` #[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))] +#[track_caller] pub fn span_lint_and_sugg<T: LintContext>( cx: &T, lint: &'static Lint, diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs new file mode 100644 index 00000000000..2e67fb65efc --- /dev/null +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Z track-diagnostics +//@no-rustfix + +// Normalize the emitted location so this doesn't need +// updating everytime someone adds or removes a line. +//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" + +#![warn(clippy::let_and_return, clippy::unnecessary_cast)] + +fn main() { + // Check the provenance of a lint sent through `LintContext::span_lint()` + let a = 3u32; + let b = a as u32; + //~^ unnecessary_cast + + // Check the provenance of a lint sent through `TyCtxt::node_span_lint()` + let c = { + let d = 42; + d + //~^ let_and_return + }; +} diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr new file mode 100644 index 00000000000..f3aca685417 --- /dev/null +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr @@ -0,0 +1,29 @@ +error: casting to the same type is unnecessary (`u32` -> `u32`) + --> tests/ui/track-diagnostics-clippy.rs:LL:CC + | +LL | let b = a as u32; + | ^^^^^^^^ help: try: `a` +-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC + | + = note: `-D clippy::unnecessary-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` + +error: returning the result of a `let` binding from a block + --> tests/ui/track-diagnostics-clippy.rs:LL:CC + | +LL | let d = 42; + | ----------- unnecessary `let` binding +LL | d + | ^ +-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC + | + = note: `-D clippy::let-and-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` +help: return the expression directly + | +LL ~ +LL ~ 42 + | + +error: aborting due to 2 previous errors + diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 2ecb4fc8652..adf2a7bffef 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -1,6 +1,6 @@ /// This was originally generated by collecting directives from ui tests and then extracting their /// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is -/// a best-effort approximation for diagnostics. Add new headers to this list when needed. +/// a best-effort approximation for diagnostics. Add new directives to this list when needed. const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ // tidy-alphabetical-start "add-core-stubs", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/directives.rs index 5636a146b0f..a6242cf0c22 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/directives.rs @@ -11,10 +11,10 @@ use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::debuggers::{extract_cdb_version, extract_gdb_version}; +use crate::directives::auxiliary::{AuxProps, parse_and_update_aux}; +use crate::directives::needs::CachedNeedsConditions; use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; -use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; -use crate::header::needs::CachedNeedsConditions; use crate::help; use crate::util::static_regex; @@ -24,11 +24,11 @@ mod needs; #[cfg(test)] mod tests; -pub struct HeadersCache { +pub struct DirectivesCache { needs: CachedNeedsConditions, } -impl HeadersCache { +impl DirectivesCache { pub fn load(config: &Config) -> Self { Self { needs: CachedNeedsConditions::load(config) } } @@ -54,7 +54,7 @@ impl EarlyProps { pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self { let mut props = EarlyProps::default(); let mut poisoned = false; - iter_header( + iter_directives( config.mode, &config.suite, &mut poisoned, @@ -138,12 +138,12 @@ pub struct TestProps { pub incremental_dir: Option<Utf8PathBuf>, // If `true`, this test will use incremental compilation. // - // This can be set manually with the `incremental` header, or implicitly + // This can be set manually with the `incremental` directive, or implicitly // by being a part of an incremental mode test. Using the `incremental` - // header should be avoided if possible; using an incremental mode test is + // directive should be avoided if possible; using an incremental mode test is // preferred. Incremental mode tests support multiple passes, which can // verify that the incremental cache can be loaded properly after being - // created. Just setting the header will only verify the behavior with + // created. Just setting the directive will only verify the behavior with // creating an incremental cache, but doesn't check that it is created // correctly. // @@ -347,7 +347,7 @@ impl TestProps { let mut poisoned = false; - iter_header( + iter_directives( config.mode, &config.suite, &mut poisoned, @@ -642,11 +642,11 @@ impl TestProps { let check_ui = |mode: &str| { // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows if config.mode != Mode::Ui && config.mode != Mode::Crashes { - panic!("`{}-fail` header is only supported in UI tests", mode); + panic!("`{}-fail` directive is only supported in UI tests", mode); } }; if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") { - panic!("`compile-fail` header is useless in UI tests"); + panic!("`compile-fail` directive is useless in UI tests"); } let fail_mode = if config.parse_name_directive(ln, "check-fail") { check_ui("check"); @@ -662,7 +662,7 @@ impl TestProps { }; match (self.fail_mode, fail_mode) { (None, Some(_)) => self.fail_mode = fail_mode, - (Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"), + (Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"), (_, None) => {} } } @@ -674,10 +674,10 @@ impl TestProps { (Mode::Codegen, "build-pass") => (), (Mode::Incremental, _) => { if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) { - panic!("`{s}` header is only supported in `cfail` incremental tests") + panic!("`{s}` directive is only supported in `cfail` incremental tests") } } - (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"), + (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"), }; let pass_mode = if config.parse_name_directive(ln, "check-pass") { check_no_run("check-pass"); @@ -693,7 +693,7 @@ impl TestProps { }; match (self.pass_mode, pass_mode) { (None, Some(_)) => self.pass_mode = pass_mode, - (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"), + (Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"), (_, None) => {} } } @@ -794,7 +794,7 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"]; /// The (partly) broken-down contents of a line containing a test directive, -/// which [`iter_header`] passes to its callback function. +/// which [`iter_directives`] passes to its callback function. /// /// For example: /// @@ -867,7 +867,7 @@ pub(crate) fn check_directive<'a>( const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; -fn iter_header( +fn iter_directives( mode: Mode, _suite: &str, poisoned: &mut bool, @@ -1163,8 +1163,7 @@ enum NormalizeKind { Stderr64bit, } -/// Parses the regex and replacement values of a `//@ normalize-*` header, -/// in the format: +/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format: /// ```text /// "REGEX" -> "REPLACEMENT" /// ``` @@ -1373,7 +1372,7 @@ where pub(crate) fn make_test_description<R: Read>( config: &Config, - cache: &HeadersCache, + cache: &DirectivesCache, name: String, path: &Utf8Path, src: R, @@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description<R: Read>( let mut local_poisoned = false; // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives. - iter_header( + iter_directives( config.mode, &config.suite, &mut local_poisoned, diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 0e1f3a785f8..cdb75f6ffa9 100644 --- a/src/tools/compiletest/src/header/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -3,8 +3,8 @@ use std::iter; +use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; -use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index f1f1384afb9..35f6a9e1644 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use crate::common::{CompareMode, Config, Debugger}; -use crate::header::IgnoreDecision; +use crate::directives::IgnoreDecision; const EXTRA_ARCHS: &[&str] = &["spirv"]; diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/directives/needs.rs index b1165f4bb18..ee46f4c70cb 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,5 +1,5 @@ use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; -use crate::header::{IgnoreDecision, llvm_has_libzstd}; +use crate::directives::{IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs index fea66a5e07b..fea66a5e07b 100644 --- a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs +++ b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs index 99834b14c1e..99834b14c1e 100644 --- a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs +++ b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile index 4b565e0e6df..4b565e0e6df 100644 --- a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile +++ b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs index d4406031043..d4406031043 100644 --- a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs +++ b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 31b49b09bcd..d4570f82677 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -4,7 +4,7 @@ use camino::Utf8Path; use semver::Version; use super::{ - EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header, + DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives, parse_normalize_rule, }; use crate::common::{Config, Debugger, Mode}; @@ -17,9 +17,9 @@ fn make_test_description<R: Read>( src: R, revision: Option<&str>, ) -> CollectedTestDesc { - let cache = HeadersCache::load(config); + let cache = DirectivesCache::load(config); let mut poisoned = false; - let test = crate::header::make_test_description( + let test = crate::directives::make_test_description( config, &cache, name, @@ -785,7 +785,7 @@ fn threads_support() { fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { let rdr = std::io::Cursor::new(&buf); - iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); + iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 09de3eb4c70..dfce4b8b408 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -12,9 +12,9 @@ pub mod common; pub mod compute_diff; mod debuggers; pub mod diagnostics; +pub mod directives; pub mod errors; mod executor; -pub mod header; mod json; mod raise_fd_limit; mod read2; @@ -37,13 +37,13 @@ use rayon::iter::{ParallelBridge, ParallelIterator}; use tracing::debug; use walkdir::WalkDir; -use self::header::{EarlyProps, make_test_description}; +use self::directives::{EarlyProps, make_test_description}; use crate::common::{ CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, output_base_dir, output_relative_path, }; +use crate::directives::DirectivesCache; use crate::executor::{CollectedTest, ColorConfig, OutputFormat}; -use crate::header::HeadersCache; use crate::util::logv; /// Creates the `Config` instance for this invocation of compiletest. @@ -254,8 +254,8 @@ pub fn parse_config(args: Vec<String>) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else( - || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else( + || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); let run_ignored = matches.opt_present("ignored"); @@ -618,7 +618,7 @@ pub fn run_tests(config: Arc<Config>) { /// Read-only context data used during test collection. struct TestCollectorCx { config: Arc<Config>, - cache: HeadersCache, + cache: DirectivesCache, common_inputs_stamp: Stamp, modified_tests: Vec<Utf8PathBuf>, } @@ -654,7 +654,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| { fatal!("modified_tests: {}: {err}", config.src_test_suite_root); }); - let cache = HeadersCache::load(&config); + let cache = DirectivesCache::load(&config); let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests }; let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new("")) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 53b5990d3cd..f8bf4ee3022 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -23,8 +23,8 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; +use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; -use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; use crate::{ColorConfig, help, json, stamp_file_path, warning}; @@ -2039,7 +2039,7 @@ impl<'test> TestCx<'test> { // Provide more context on failures. filecheck.args(&["--dump-input-context", "100"]); - // Add custom flags supplied by the `filecheck-flags:` test header. + // Add custom flags supplied by the `filecheck-flags:` test directive. filecheck.args(&self.props.filecheck_flags); // FIXME(jieyouxu): don't pass an empty Path diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 31240dff9a1..d9e1e4dfc8d 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -49,7 +49,7 @@ impl TestCx<'_> { std::fs::remove_file(pdb_file).unwrap(); } - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compile_result = self.compile_test(should_run, Emit::None); if !compile_result.status.success() { @@ -135,7 +135,7 @@ impl TestCx<'_> { .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compiler_run_result = self.compile_test(should_run, Emit::None); if !compiler_run_result.status.success() { @@ -359,7 +359,7 @@ impl TestCx<'_> { } fn run_debuginfo_lldb_test_no_opt(&self) { - // compile test file (it should have 'compile-flags:-g' in the header) + // compile test file (it should have 'compile-flags:-g' in the directive) let should_run = self.run_if_enabled(); let compile_result = self.compile_test(should_run, Emit::None); if !compile_result.status.success() { diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index cc50a918f75..f6bc85cd051 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -52,10 +52,10 @@ impl TestCx<'_> { // don't test rustfix with nll right now } else if self.config.rustfix_coverage { // Find out which tests have `MachineApplicable` suggestions but are missing - // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. + // `run-rustfix` or `run-rustfix-only-machine-applicable` directives. // // This will return an empty `Vec` in case the executed test file has a - // `compile-flags: --error-format=xxxx` header with a value other than `json`. + // `compile-flags: --error-format=xxxx` directive with a value other than `json`. let suggestions = get_suggestions_from_json( &rustfix_input, &HashSet::new(), diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 1796120cf8a..3cc38fa087c 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -466,17 +466,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some((alloc_id, Size::from_bytes(rel_offset))) } - /// Prepare all exposed memory for a native call. - /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all reachable provenances as exposed - /// and overwrite them with `Provenance::WILDCARD`. - fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - // We need to make a deep copy of this list, but it's fine; it also serves as scratch space - // for the search within `prepare_for_native_call`. - let exposed: Vec<AllocId> = - this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect(); - this.prepare_for_native_call(exposed) + /// Return a list of all exposed allocations. + fn exposed_allocs(&self) -> Vec<AllocId> { + let this = self.eval_context_ref(); + this.machine.alloc_addresses.borrow().exposed.iter().copied().collect() } } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index ed1851a19ae..4efa7dd4dcf 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -457,6 +457,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap"))) } + "assert_inhabited" | "assert_zero_valid" | "assert_mem_uninitialized_valid" => { + // Make these a NOP, so we get the better Miri-native error messages. + } + _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 9c659f65e50..9b30d8ce78b 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -198,7 +198,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut libffi_args = Vec::<CArg>::with_capacity(args.len()); for arg in args.iter() { if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { - throw_unsup_format!("only scalar argument types are support for native calls") + throw_unsup_format!("only scalar argument types are supported for native calls") } let imm = this.read_immediate(arg)?; libffi_args.push(imm_to_carg(&imm, this)?); @@ -224,16 +224,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.expose_provenance(prov)?; } } - - // Prepare all exposed memory. - this.prepare_exposed_for_native_call()?; - - // Convert them to `libffi::high::Arg` type. + // Convert arguments to `libffi::high::Arg` type. let libffi_args = libffi_args .iter() .map(|arg| arg.arg_downcast()) .collect::<Vec<libffi::high::Arg<'_>>>(); + // Prepare all exposed memory (both previously exposed, and just newly exposed since a + // pointer was passed as argument). + this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| { + // If there is no data behind this pointer, skip this. + if !matches!(info.kind, AllocKind::LiveData) { + return interp_ok(()); + } + // It's okay to get raw access, what we do does not correspond to any actual + // AM operation, it just approximates the state to account for the native call. + let alloc = this.get_alloc_raw(alloc_id)?; + // Also expose the provenance of the interpreter-level allocation, so it can + // be read by FFI. The `black_box` is defensive programming as LLVM likes + // to (incorrectly) optimize away ptr2int casts whose result is unused. + std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); + // Expose all provenances in this allocation, since the native code can do $whatever. + for prov in alloc.provenance().provenances() { + this.expose_provenance(prov)?; + } + + // Prepare for possible write from native code if mutable. + if info.mutbl.is_mut() { + let alloc = &mut this.get_alloc_raw_mut(alloc_id)?.0; + alloc.prepare_for_native_access(); + // Also expose *mutable* provenance for the interpreter-level allocation. + std::hint::black_box(alloc.get_bytes_unchecked_raw_mut().expose_provenance()); + } + + interp_ok(()) + })?; + // Call the function and store output, depending on return type in the function signature. let (ret, maybe_memevents) = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?; @@ -321,7 +347,8 @@ fn imm_to_carg<'tcx>(v: &ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<' CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()), ty::RawPtr(..) => { let s = v.to_scalar().to_pointer(cx)?.addr(); - // This relies on the `expose_provenance` in `prepare_for_native_call`. + // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback + // above. CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize())) } _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty), diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs index dd2dd346231..1dc334486c3 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs @@ -20,7 +20,7 @@ fn main() { let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit(); // Read 4 bytes from a 3-byte file. assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3); - buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + buf.assume_init(); //~ERROR: encountered uninitialized memory, but expected an integer assert_eq!(libc::close(fd), 0); } remove_file(&path).unwrap(); diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr index fadb31e3a8f..83119f087ff 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value at [3]: encountered uninitialized memory, but expected an integer --> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC | -LL | ... buf.assume_init(); - | ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | buf.assume_init(); + | ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = 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/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs index dd3246d8120..34fef6b9ee5 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,11 +1,6 @@ -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" -//@normalize-stderr-test: "\n +at [^\n]+" -> "" -//@error-in-other-file: aborted execution #![feature(never_type)] #[allow(deprecated, invalid_value)] fn main() { - let _ = unsafe { std::mem::uninitialized::<!>() }; + let _ = unsafe { std::mem::uninitialized::<!>() }; //~ERROR: constructing invalid value } diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 3db8a5be205..36642208afe 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -1,27 +1,13 @@ - -thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: -aborted execution: attempted to instantiate uninhabited type `!` -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread caused non-unwinding panic. aborting. -error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - | -LL | ABORT() - | ^ abnormal termination occurred here - | - = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `main` +error: Undefined Behavior: constructing invalid value: encountered a value of the never type `!` --> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC | LL | let _ = unsafe { std::mem::uninitialized::<!>() }; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = 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 tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs index 3d355bad626..cca2c5ae984 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,10 +1,4 @@ -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" -//@normalize-stderr-test: "\n +at [^\n]+" -> "" -//@error-in-other-file: aborted execution - #[allow(deprecated, invalid_value)] fn main() { - let _ = unsafe { std::mem::zeroed::<fn()>() }; + let _ = unsafe { std::mem::zeroed::<fn()>() }; //~ERROR: constructing invalid value } diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index a1e476328b0..53f3f8d1404 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -1,27 +1,13 @@ - -thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: -aborted execution: attempted to zero-initialize type `fn()`, which is invalid -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -thread caused non-unwinding panic. aborting. -error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - | -LL | ABORT() - | ^ abnormal termination occurred here - | - = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `main` +error: Undefined Behavior: constructing invalid value: encountered a null function pointer --> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC | LL | let _ = unsafe { std::mem::zeroed::<fn()>() }; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = 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 tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr index 1b948b062e1..0c859d72764 100644 --- a/src/tools/miri/tests/fail/validity/uninit_float.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a floating point number --> tests/fail/validity/uninit_float.rs:LL:CC | LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr index b17bdee65da..5d31e2659ee 100644 --- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer --> tests/fail/validity/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; diff --git a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr index 269af6061c2..d2e9408adbe 100644 --- a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a raw pointer --> tests/fail/validity/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index addb0af4a54..6461f38f527 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::{env, fs}; use build_helper::util::try_run; -use compiletest::header::TestProps; +use compiletest::directives::TestProps; use config::Config; mod config; diff --git a/src/tools/rustfmt/tests/source/let_chains.rs b/src/tools/rustfmt/tests/source/let_chains.rs index 0c4d8aa85ea..fc2a9310569 100644 --- a/src/tools/rustfmt/tests/source/let_chains.rs +++ b/src/tools/rustfmt/tests/source/let_chains.rs @@ -1,3 +1,5 @@ +// rustfmt-edition: 2024 + fn main() { if let x = x && x {} diff --git a/src/tools/rustfmt/tests/target/let_chains.rs b/src/tools/rustfmt/tests/target/let_chains.rs index 204937b4cac..4fd6048d914 100644 --- a/src/tools/rustfmt/tests/target/let_chains.rs +++ b/src/tools/rustfmt/tests/target/let_chains.rs @@ -1,3 +1,5 @@ +// rustfmt-edition: 2024 + fn main() { if let x = x && x diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs index 720f0712ee0..5e924544f0d 100644 --- a/src/tools/tidy/src/rustdoc_js.rs +++ b/src/tools/tidy/src/rustdoc_js.rs @@ -52,8 +52,7 @@ fn get_eslint_version() -> Option<String> { } pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) { - let eslint_version_path = - src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version"); + let eslint_version_path = src_path.join("ci/docker/host-x86_64/tidy/eslint.version"); let eslint_version = match std::fs::read_to_string(&eslint_version_path) { Ok(version) => version.trim().to_string(), Err(error) => { diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index c57ade58c30..3ac6ba3beb1 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,6 +1,12 @@ +//@ add-core-stubs //@ compile-flags: -C opt-level=0 -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)] +#![no_core] +extern crate minicore; + +use minicore::*; // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, // without needing to pointercast, and SRoA will turn that into a `bitcast`. @@ -14,7 +20,7 @@ // CHECK-NEXT: ret i32 %_0 #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { - unsafe { std::mem::transmute(x) } + unsafe { mem::transmute(x) } } // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) @@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 { // CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_byte(b: bool) -> u8 { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) @@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 { // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { - std::mem::transmute(byte) + mem::transmute(byte) } // CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p) // CHECK: ret ptr %p #[no_mangle] pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) @@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { // CHECK-NEXT: ret [[USIZE]] %_0 #[no_mangle] pub fn ptr_to_int(p: *mut u16) -> usize { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) @@ -53,7 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { // CHECK-NEXT: ret ptr %_0 #[no_mangle] pub fn int_to_ptr(i: usize) -> *mut u16 { - unsafe { std::mem::transmute(i) } + unsafe { mem::transmute(i) } } // This is the one case where signedness matters to transmuting: @@ -70,7 +76,7 @@ pub enum FakeBoolSigned { // CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) @@ -78,7 +84,7 @@ pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } #[repr(u8)] @@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned { // CHECK: ret i1 %b #[no_mangle] pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) // CHECK: ret i1 %b #[no_mangle] pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } +} + +#[repr(simd)] +struct S([i64; 1]); + +// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) +// CHECK: bitcast <1 x i64> %b to i64 +// CHECK: ret i64 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) +// CHECK: bitcast i64 %b to <1 x i64> +// CHECK: ret <1 x i64> +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S { + unsafe { mem::transmute(b) } } diff --git a/tests/coverage/branch/if-let.coverage b/tests/coverage/branch/if-let.coverage index 9a3f0113f75..e55da7fb726 100644 --- a/tests/coverage/branch/if-let.coverage +++ b/tests/coverage/branch/if-let.coverage @@ -1,5 +1,5 @@ - LL| |#![feature(coverage_attribute, let_chains)] - LL| |//@ edition: 2021 + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2024 LL| |//@ compile-flags: -Zcoverage-options=branch LL| |//@ llvm-cov-flags: --show-branches=count LL| | diff --git a/tests/coverage/branch/if-let.rs b/tests/coverage/branch/if-let.rs index 13db00a82b1..6f88de54cda 100644 --- a/tests/coverage/branch/if-let.rs +++ b/tests/coverage/branch/if-let.rs @@ -1,5 +1,5 @@ -#![feature(coverage_attribute, let_chains)] -//@ edition: 2021 +#![feature(coverage_attribute)] +//@ edition: 2024 //@ compile-flags: -Zcoverage-options=branch //@ llvm-cov-flags: --show-branches=count diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index 97273ceb195..0df9cc2a659 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -129,13 +129,13 @@ define-function: ("check-line-numbers-existence", [], block { wait-for-local-storage-false: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. - assert-css: ("[data-nosnippet]", { "display": "inline-block"}) + assert-css: ("[data-nosnippet]", { "display": "block"}) // Now disabling the setting. click: "input#line-numbers" wait-for-local-storage: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. - assert-css: ("[data-nosnippet]", { "display": "inline-block"}) + assert-css: ("[data-nosnippet]", { "display": "block"}) // Closing settings menu. click: "#settings-menu" wait-for-css: ("#settings", {"display": "none"}) diff --git a/tests/rustdoc-gui/scrape-examples-button-focus.goml b/tests/rustdoc-gui/scrape-examples-button-focus.goml index 12246a37661..f6e836e2360 100644 --- a/tests/rustdoc-gui/scrape-examples-button-focus.goml +++ b/tests/rustdoc-gui/scrape-examples-button-focus.goml @@ -5,7 +5,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" // The next/prev buttons vertically scroll the code viewport between examples move-cursor-to: ".scraped-example-list > .scraped-example" wait-for: ".scraped-example-list > .scraped-example .next" -store-value: (initialScrollTop, 250) +store-value: (initialScrollTop, 236) assert-property: (".scraped-example-list > .scraped-example .rust", { "scrollTop": |initialScrollTop|, }, NEAR) diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml index cb2fd3052cd..0dab9c72ea9 100644 --- a/tests/rustdoc-gui/source-code-wrapping.goml +++ b/tests/rustdoc-gui/source-code-wrapping.goml @@ -31,17 +31,32 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html" click: "#settings-menu" wait-for: "#settings" -store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height}) -store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height}) +store-property: (".example-wrap .rust code", {"scrollWidth": rust_width, "scrollHeight": rust_height}) +store-property: (".example-wrap .language-text code", {"scrollWidth": txt_width, "scrollHeight": txt_height}) call-function: ("click-code-wrapping", {"expected": "true"}) -wait-for-size-false: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|}) +wait-for-property-false: ( + ".example-wrap .rust code", + {"scrollWidth": |rust_width|, "scrollHeight": |rust_height|}, +) -store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height}) -store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height}) +store-property: ( + ".example-wrap .rust code", + {"scrollWidth": new_rust_width, "scrollHeight": new_rust_height}, +) +store-property: ( + ".example-wrap .language-text code", + {"scrollWidth": new_txt_width, "scrollHeight": new_txt_height}, +) assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height| assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height| call-function: ("click-code-wrapping", {"expected": "false"}) -wait-for-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|}) -assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|}) +wait-for-property: ( + ".example-wrap .rust code", + {"scrollWidth": |rust_width|, "scrollHeight": |rust_height|}, +) +assert-property: ( + ".example-wrap .language-text code", + {"scrollWidth": |txt_width|, "scrollHeight": |txt_height|}, +) diff --git a/tests/ui/attributes/crate-type-macro-empty.rs b/tests/ui/attributes/crate-type-macro-empty.rs index 5ff7fc002fd..217ff598f7a 100644 --- a/tests/ui/attributes/crate-type-macro-empty.rs +++ b/tests/ui/attributes/crate-type-macro-empty.rs @@ -2,6 +2,6 @@ #[crate_type = foo!()] //~^ ERROR cannot find macro `foo` in this scope -macro_rules! foo {} //~ ERROR unexpected end of macro invocation +macro_rules! foo {} //~ ERROR macros must contain at least one rule fn main() {} diff --git a/tests/ui/attributes/crate-type-macro-empty.stderr b/tests/ui/attributes/crate-type-macro-empty.stderr index e48d3d95470..130fa454ca1 100644 --- a/tests/ui/attributes/crate-type-macro-empty.stderr +++ b/tests/ui/attributes/crate-type-macro-empty.stderr @@ -1,8 +1,8 @@ -error: unexpected end of macro invocation +error: macros must contain at least one rule --> $DIR/crate-type-macro-empty.rs:5:1 | LL | macro_rules! foo {} - | ^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^^^^ error: cannot find macro `foo` in this scope --> $DIR/crate-type-macro-empty.rs:2:16 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 532c1ab13d1..2484974cdc2 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` + = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/drop/drop-order-comparisons-let-chains.rs b/tests/ui/drop/drop-order-comparisons-let-chains.rs new file mode 100644 index 00000000000..5dea5e1a580 --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons-let-chains.rs @@ -0,0 +1,145 @@ +// See drop-order-comparisons.rs + +//@ edition: 2024 +//@ run-pass + +#![feature(if_let_guard)] + +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +fn t_guard_if_let_chains_then() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() => { + e.mark(3); + } + _ => {} + }; + e.assert(9); +} + +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) {} else { + e.mark(9); + }; + e.assert(9); +} + +fn t_guard_if_let_chains_then_else() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) => {} + _ => { + e.mark(9); + } + }; + e.assert(9); +} + +fn main() { + t_if_let_chains_then(); + t_guard_if_let_chains_then(); + t_if_let_chains_then_else(); + t_guard_if_let_chains_then_else(); +} + +// # Test scaffolding + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A buffer to track the order of events. +/// +/// First, numbered events are logged into this buffer. +/// +/// Then, `assert` is called to verify that the correct number of +/// events were logged, and that they were logged in the expected +/// order. +struct Events(RefCell<Option<Vec<u64>>>); + +impl Events { + const fn new() -> Self { + Self(RefCell::new(Some(Vec::new()))) + } + #[track_caller] + fn assert(&self, max: u64) { + let buf = &self.0; + let v1 = buf.borrow().as_ref().unwrap().clone(); + let mut v2 = buf.borrow().as_ref().unwrap().clone(); + *buf.borrow_mut() = None; + v2.sort(); + let uniq_len = v2.iter().collect::<HashSet<_>>().len(); + // Check that the sequence is sorted. + assert_eq!(v1, v2); + // Check that there are no duplicates. + assert_eq!(v2.len(), uniq_len); + // Check that the length is the expected one. + assert_eq!(max, uniq_len as u64); + // Check that the last marker is the expected one. + assert_eq!(v2.last().unwrap(), &max); + } + /// Return an `Ok` value that logs its drop. + fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> { + Ok(LogDrop(self, m)) + } + /// Return an `Err` value that logs its drop. + fn err(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> { + Err(LogDrop(self, m)) + } + /// Log an event. + fn mark(&self, m: u64) { + self.0.borrow_mut().as_mut().unwrap().push(m); + } +} + +impl Drop for Events { + fn drop(&mut self) { + if self.0.borrow().is_some() { + panic!("failed to call `Events::assert()`"); + } + } +} + +/// A type that logs its drop events. +struct LogDrop<'b>(&'b Events, u64); + +impl<'b> Drop for LogDrop<'b> { + fn drop(&mut self) { + self.0.mark(self.1); + } +} diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed index 42f805923ec..b0f6eb93f70 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.fixed +++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed @@ -1,3 +1,6 @@ +// N.B. drop-order-comparisons-let-chains.rs is part of this test. +// It is separate because let chains cannot be parsed before Rust 2024. +// // This tests various aspects of the drop order with a focus on: // // - The lifetime of temporaries with the `if let` construct (and with @@ -25,7 +28,6 @@ //@ run-pass #![feature(if_let_guard)] -#![cfg_attr(e2021, feature(let_chains))] #![cfg_attr(e2021, warn(rust_2024_compatibility))] fn t_bindings() { @@ -313,59 +315,6 @@ fn t_let_else_chained_then() { #[cfg(e2021)] #[rustfmt::skip] -fn t_if_let_chains_then() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(8) - && let Ok(_) = e.ok(7).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.ok(6).as_ref() { - e.mark(3); - }; - e.assert(9); -} - -#[cfg(e2024)] -#[rustfmt::skip] -fn t_if_let_chains_then() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(8) - && let Ok(_) = e.ok(7) - && let Ok(_) = e.ok(6).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(4).as_ref() { - e.mark(3); - }; - e.assert(9); -} - -#[rustfmt::skip] -fn t_guard_if_let_chains_then() { - let e = Events::new(); - _ = match () { - () if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(8) - && let Ok(_) = e.ok(7) - && let Ok(_) = e.ok(6).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(4).as_ref() => { - e.mark(3); - } - _ => {} - }; - e.assert(9); -} - -#[cfg(e2021)] -#[rustfmt::skip] fn t_if_let_nested_else() { let e = Events::new(); _ = if e.err(1).is_ok() {} else { @@ -470,59 +419,6 @@ fn t_let_else_chained_then_else() { e.assert(9); } -#[cfg(e2021)] -#[rustfmt::skip] -fn t_if_let_chains_then_else() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.ok(8) - && let Ok(_) = e.ok(7).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(3) - && let Ok(_) = e.err(6) {} else { - e.mark(5); - }; - e.assert(9); -} - -#[cfg(e2024)] -#[rustfmt::skip] -fn t_if_let_chains_then_else() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(8).is_ok() - && let Ok(_v) = e.ok(7) - && let Ok(_) = e.ok(6) - && let Ok(_) = e.ok(5).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.err(3) {} else { - e.mark(9); - }; - e.assert(9); -} - -#[rustfmt::skip] -fn t_guard_if_let_chains_then_else() { - let e = Events::new(); - _ = match () { - () if e.ok(1).is_ok() - && let true = e.ok(8).is_ok() - && let Ok(_v) = e.ok(7) - && let Ok(_) = e.ok(6) - && let Ok(_) = e.ok(5).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.err(3) => {} - _ => { - e.mark(9); - } - }; - e.assert(9); -} - fn main() { t_bindings(); t_tuples(); @@ -540,13 +436,9 @@ fn main() { t_if_let_else_tailexpr(); t_if_let_nested_then(); t_let_else_chained_then(); - t_if_let_chains_then(); - t_guard_if_let_chains_then(); t_if_let_nested_else(); t_if_let_nested_then_else(); t_let_else_chained_then_else(); - t_if_let_chains_then_else(); - t_guard_if_let_chains_then_else(); } // # Test scaffolding diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr index 8b93376cc0d..15a3f274514 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.stderr +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -1,5 +1,5 @@ warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:77:9 + --> $DIR/drop-order-comparisons.rs:79:9 | LL | _ = ({ | _________- @@ -29,35 +29,35 @@ LL | | }, e.mark(3), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> note: `#3` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `_v` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here - --> $DIR/drop-order-comparisons.rs:29:25 + --> $DIR/drop-order-comparisons.rs:31:25 | LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))] | ^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]` warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:101:45 + --> $DIR/drop-order-comparisons.rs:103:45 | LL | _ = ({ | _________- @@ -77,19 +77,19 @@ LL | | }, e.mark(1), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:101:19 + --> $DIR/drop-order-comparisons.rs:103:19 | LL | _ = ({ | _________- @@ -109,19 +109,19 @@ LL | | }, e.mark(1), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:222:24 + --> $DIR/drop-order-comparisons.rs:224:24 | LL | _ = ({ | _________- @@ -141,19 +141,19 @@ LL | | }, e.mark(2), e.ok(3)); = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:248:24 + --> $DIR/drop-order-comparisons.rs:250:24 | LL | _ = ({ | _________- @@ -173,19 +173,19 @@ LL | | }, e.mark(2), e.ok(3)); = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:124:13 + --> $DIR/drop-order-comparisons.rs:126:13 | LL | _ = (if let Ok(_) = e.ok(4).as_ref() { | ^^^^^^^^^^^^-------^^^^^^^^^ @@ -195,12 +195,12 @@ LL | _ = (if let Ok(_) = e.ok(4).as_ref() { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:128:5 + --> $DIR/drop-order-comparisons.rs:130:5 | LL | }, e.mark(2), e.ok(3)); | ^ @@ -215,7 +215,7 @@ LL ~ } _ => {}}, e.mark(2), e.ok(3)); | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:146:13 + --> $DIR/drop-order-comparisons.rs:148:13 | LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -225,12 +225,12 @@ LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:146:44 + --> $DIR/drop-order-comparisons.rs:148:44 | LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | ^ @@ -244,7 +244,7 @@ LL ~ }}, e.mark(2), e.ok(3)); | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:248:12 + --> $DIR/drop-order-comparisons.rs:250:12 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -254,12 +254,12 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:248:43 + --> $DIR/drop-order-comparisons.rs:250:43 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ @@ -273,7 +273,7 @@ LL ~ }} | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:372:12 + --> $DIR/drop-order-comparisons.rs:321:12 | LL | if let true = e.err(9).is_ok() {} else { | ^^^^^^^^^^^--------^^^^^^^^ @@ -283,12 +283,12 @@ LL | if let true = e.err(9).is_ok() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:372:41 + --> $DIR/drop-order-comparisons.rs:321:41 | LL | if let true = e.err(9).is_ok() {} else { | ^ @@ -302,7 +302,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:375:12 + --> $DIR/drop-order-comparisons.rs:324:12 | LL | if let Ok(_v) = e.err(8) {} else { | ^^^^^^^^^^^^^-------- @@ -312,12 +312,12 @@ LL | if let Ok(_v) = e.err(8) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:375:35 + --> $DIR/drop-order-comparisons.rs:324:35 | LL | if let Ok(_v) = e.err(8) {} else { | ^ @@ -331,7 +331,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:378:12 + --> $DIR/drop-order-comparisons.rs:327:12 | LL | if let Ok(_) = e.err(7) {} else { | ^^^^^^^^^^^^-------- @@ -341,12 +341,12 @@ LL | if let Ok(_) = e.err(7) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:378:34 + --> $DIR/drop-order-comparisons.rs:327:34 | LL | if let Ok(_) = e.err(7) {} else { | ^ @@ -360,7 +360,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:381:12 + --> $DIR/drop-order-comparisons.rs:330:12 | LL | if let Ok(_) = e.err(6).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -370,12 +370,12 @@ LL | if let Ok(_) = e.err(6).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:381:43 + --> $DIR/drop-order-comparisons.rs:330:43 | LL | if let Ok(_) = e.err(6).as_ref() {} else { | ^ @@ -389,7 +389,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:385:12 + --> $DIR/drop-order-comparisons.rs:334:12 | LL | if let Ok(_v) = e.err(5) {} else { | ^^^^^^^^^^^^^-------- @@ -399,12 +399,12 @@ LL | if let Ok(_v) = e.err(5) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:385:35 + --> $DIR/drop-order-comparisons.rs:334:35 | LL | if let Ok(_v) = e.err(5) {} else { | ^ @@ -418,7 +418,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:388:12 + --> $DIR/drop-order-comparisons.rs:337:12 | LL | if let Ok(_) = e.err(4) {} else { | ^^^^^^^^^^^^-------- @@ -428,12 +428,12 @@ LL | if let Ok(_) = e.err(4) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:388:34 + --> $DIR/drop-order-comparisons.rs:337:34 | LL | if let Ok(_) = e.err(4) {} else { | ^ @@ -447,7 +447,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:424:12 + --> $DIR/drop-order-comparisons.rs:373:12 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -457,12 +457,12 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:612:1 + --> $DIR/drop-order-comparisons.rs:504:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:424:43 + --> $DIR/drop-order-comparisons.rs:373:43 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs index e7425159aa2..257c0c14ecf 100644 --- a/tests/ui/drop/drop-order-comparisons.rs +++ b/tests/ui/drop/drop-order-comparisons.rs @@ -1,3 +1,6 @@ +// N.B. drop-order-comparisons-let-chains.rs is part of this test. +// It is separate because let chains cannot be parsed before Rust 2024. +// // This tests various aspects of the drop order with a focus on: // // - The lifetime of temporaries with the `if let` construct (and with @@ -25,7 +28,6 @@ //@ run-pass #![feature(if_let_guard)] -#![cfg_attr(e2021, feature(let_chains))] #![cfg_attr(e2021, warn(rust_2024_compatibility))] fn t_bindings() { @@ -313,59 +315,6 @@ fn t_let_else_chained_then() { #[cfg(e2021)] #[rustfmt::skip] -fn t_if_let_chains_then() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(8) - && let Ok(_) = e.ok(7).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.ok(6).as_ref() { - e.mark(3); - }; - e.assert(9); -} - -#[cfg(e2024)] -#[rustfmt::skip] -fn t_if_let_chains_then() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(8) - && let Ok(_) = e.ok(7) - && let Ok(_) = e.ok(6).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(4).as_ref() { - e.mark(3); - }; - e.assert(9); -} - -#[rustfmt::skip] -fn t_guard_if_let_chains_then() { - let e = Events::new(); - _ = match () { - () if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(8) - && let Ok(_) = e.ok(7) - && let Ok(_) = e.ok(6).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(5) - && let Ok(_) = e.ok(4).as_ref() => { - e.mark(3); - } - _ => {} - }; - e.assert(9); -} - -#[cfg(e2021)] -#[rustfmt::skip] fn t_if_let_nested_else() { let e = Events::new(); _ = if e.err(1).is_ok() {} else { @@ -470,59 +419,6 @@ fn t_let_else_chained_then_else() { e.assert(9); } -#[cfg(e2021)] -#[rustfmt::skip] -fn t_if_let_chains_then_else() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(9).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.ok(8) - && let Ok(_) = e.ok(7).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(3) - && let Ok(_) = e.err(6) {} else { - e.mark(5); - }; - e.assert(9); -} - -#[cfg(e2024)] -#[rustfmt::skip] -fn t_if_let_chains_then_else() { - let e = Events::new(); - _ = if e.ok(1).is_ok() - && let true = e.ok(8).is_ok() - && let Ok(_v) = e.ok(7) - && let Ok(_) = e.ok(6) - && let Ok(_) = e.ok(5).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.err(3) {} else { - e.mark(9); - }; - e.assert(9); -} - -#[rustfmt::skip] -fn t_guard_if_let_chains_then_else() { - let e = Events::new(); - _ = match () { - () if e.ok(1).is_ok() - && let true = e.ok(8).is_ok() - && let Ok(_v) = e.ok(7) - && let Ok(_) = e.ok(6) - && let Ok(_) = e.ok(5).as_ref() - && e.ok(2).is_ok() - && let Ok(_v) = e.ok(4) - && let Ok(_) = e.err(3) => {} - _ => { - e.mark(9); - } - }; - e.assert(9); -} - fn main() { t_bindings(); t_tuples(); @@ -540,13 +436,9 @@ fn main() { t_if_let_else_tailexpr(); t_if_let_nested_then(); t_let_else_chained_then(); - t_if_let_chains_then(); - t_guard_if_let_chains_then(); t_if_let_nested_else(); t_if_let_nested_then_else(); t_let_else_chained_then_else(); - t_if_let_chains_then_else(); - t_guard_if_let_chains_then_else(); } // # Test scaffolding diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs index 34b1a0e8f75..ead498a21c3 100644 --- a/tests/ui/drop/drop_order.rs +++ b/tests/ui/drop/drop_order.rs @@ -5,8 +5,6 @@ //@ [edition2024] compile-flags: -Z lint-mir //@ [edition2024] edition: 2024 -#![cfg_attr(edition2021, feature(let_chains))] - use std::cell::RefCell; use std::convert::TryInto; @@ -210,68 +208,6 @@ impl DropOrderCollector { } } - fn let_chain(&self) { - // take the "then" branch - if self.option_loud_drop(1).is_some() // 1 - && self.option_loud_drop(2).is_some() // 2 - && let Some(_d) = self.option_loud_drop(4) { // 4 - self.print(3); // 3 - } - - #[cfg(edition2021)] - // take the "else" branch - if self.option_loud_drop(5).is_some() // 1 - && self.option_loud_drop(6).is_some() // 2 - && let None = self.option_loud_drop(8) { // 4 - unreachable!(); - } else { - self.print(7); // 3 - } - #[cfg(edition2024)] - // take the "else" branch - if self.option_loud_drop(5).is_some() // 1 - && self.option_loud_drop(6).is_some() // 2 - && let None = self.option_loud_drop(7) { // 4 - unreachable!(); - } else { - self.print(8); // 3 - } - - // let exprs interspersed - if self.option_loud_drop(9).is_some() // 1 - && let Some(_d) = self.option_loud_drop(13) // 5 - && self.option_loud_drop(10).is_some() // 2 - && let Some(_e) = self.option_loud_drop(12) { // 4 - self.print(11); // 3 - } - - // let exprs first - if let Some(_d) = self.option_loud_drop(18) // 5 - && let Some(_e) = self.option_loud_drop(17) // 4 - && self.option_loud_drop(14).is_some() // 1 - && self.option_loud_drop(15).is_some() { // 2 - self.print(16); // 3 - } - - // let exprs last - if self.option_loud_drop(19).is_some() // 1 - && self.option_loud_drop(20).is_some() // 2 - && let Some(_d) = self.option_loud_drop(23) // 5 - && let Some(_e) = self.option_loud_drop(22) { // 4 - self.print(21); // 3 - } - } - - fn while_(&self) { - let mut v = self.option_loud_drop(4); - while let Some(_d) = v - && self.option_loud_drop(1).is_some() - && self.option_loud_drop(2).is_some() { - self.print(3); - v = None; - } - } - fn assert_sorted(self) { assert!( self.0 @@ -313,14 +249,4 @@ fn main() { let collector = DropOrderCollector::default(); collector.match_(); collector.assert_sorted(); - - println!("-- let chain --"); - let collector = DropOrderCollector::default(); - collector.let_chain(); - collector.assert_sorted(); - - println!("-- while --"); - let collector = DropOrderCollector::default(); - collector.while_(); - collector.assert_sorted(); } diff --git a/tests/ui/drop/drop_order_let_chain.rs b/tests/ui/drop/drop_order_let_chain.rs new file mode 100644 index 00000000000..8d1b71c4dab --- /dev/null +++ b/tests/ui/drop/drop_order_let_chain.rs @@ -0,0 +1,103 @@ +//@ run-pass +//@ compile-flags: -Z validate-mir +//@ edition: 2024 + +use std::cell::RefCell; +use std::convert::TryInto; + +#[derive(Default)] +struct DropOrderCollector(RefCell<Vec<u32>>); + +struct LoudDrop<'a>(&'a DropOrderCollector, u32); + +impl Drop for LoudDrop<'_> { + fn drop(&mut self) { + println!("{}", self.1); + self.0.0.borrow_mut().push(self.1); + } +} + +impl DropOrderCollector { + fn option_loud_drop(&self, n: u32) -> Option<LoudDrop<'_>> { + Some(LoudDrop(self, n)) + } + + fn print(&self, n: u32) { + println!("{}", n); + self.0.borrow_mut().push(n) + } + + fn let_chain(&self) { + // take the "then" branch + if self.option_loud_drop(1).is_some() // 1 + && self.option_loud_drop(2).is_some() // 2 + && let Some(_d) = self.option_loud_drop(4) { // 4 + self.print(3); // 3 + } + + // take the "else" branch + if self.option_loud_drop(5).is_some() // 1 + && self.option_loud_drop(6).is_some() // 2 + && let None = self.option_loud_drop(7) { // 4 + unreachable!(); + } else { + self.print(8); // 3 + } + + // let exprs interspersed + if self.option_loud_drop(9).is_some() // 1 + && let Some(_d) = self.option_loud_drop(13) // 5 + && self.option_loud_drop(10).is_some() // 2 + && let Some(_e) = self.option_loud_drop(12) { // 4 + self.print(11); // 3 + } + + // let exprs first + if let Some(_d) = self.option_loud_drop(18) // 5 + && let Some(_e) = self.option_loud_drop(17) // 4 + && self.option_loud_drop(14).is_some() // 1 + && self.option_loud_drop(15).is_some() { // 2 + self.print(16); // 3 + } + + // let exprs last + if self.option_loud_drop(19).is_some() // 1 + && self.option_loud_drop(20).is_some() // 2 + && let Some(_d) = self.option_loud_drop(23) // 5 + && let Some(_e) = self.option_loud_drop(22) { // 4 + self.print(21); // 3 + } + } + + fn while_(&self) { + let mut v = self.option_loud_drop(4); + while let Some(_d) = v + && self.option_loud_drop(1).is_some() + && self.option_loud_drop(2).is_some() { + self.print(3); + v = None; + } + } + + fn assert_sorted(self) { + assert!( + self.0 + .into_inner() + .into_iter() + .enumerate() + .all(|(idx, item)| idx + 1 == item.try_into().unwrap()) + ); + } +} + +fn main() { + println!("-- let chain --"); + let collector = DropOrderCollector::default(); + collector.let_chain(); + collector.assert_sorted(); + + println!("-- while --"); + let collector = DropOrderCollector::default(); + collector.while_(); + collector.assert_sorted(); +} diff --git a/tests/ui/drop/issue-100276.rs b/tests/ui/drop/issue-100276.rs index 5d212b3a0a9..c8e25e48b15 100644 --- a/tests/ui/drop/issue-100276.rs +++ b/tests/ui/drop/issue-100276.rs @@ -1,11 +1,6 @@ //@ check-pass -//@ compile-flags: -Z validate-mir -//@ revisions: edition2021 edition2024 -//@ [edition2021] edition: 2021 -//@ [edition2024] compile-flags: -Z lint-mir -//@ [edition2024] edition: 2024 - -#![cfg_attr(edition2021, feature(let_chains))] +//@ compile-flags: -Z lint-mir -Z validate-mir +//@ edition: 2024 fn let_chains(entry: std::io::Result<std::fs::DirEntry>) { if let Ok(entry) = entry diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr index 95a5a58ab85..88c08cb94ba 100644 --- a/tests/ui/error-codes/E0637.stderr +++ b/tests/ui/error-codes/E0637.stderr @@ -3,6 +3,8 @@ error[E0637]: `'_` cannot be used here | LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/E0637.rs:1:62 diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 02b9e2f06ee..9280dfdf92e 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -387,14 +387,6 @@ LL | #![link()] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 - | -LL | #![cold] - | ^^^^^^^^ cannot be applied to crates - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: attribute should be applied to a foreign function or static --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 | @@ -417,6 +409,14 @@ warning: `#[must_use]` has no effect when applied to a module LL | #![must_use] | ^^^^^^^^^^^^ +warning: attribute should be applied to a function definition + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 + | +LL | #![cold] + | ^^^^^^^^ cannot be applied to crates + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed index a8c8dd1d512..be322a31363 100644 --- a/tests/ui/lint/lint-unnecessary-parens.fixed +++ b/tests/ui/lint/lint-unnecessary-parens.fixed @@ -1,5 +1,6 @@ //@ run-rustfix +#![feature(impl_trait_in_fn_trait_return)] #![deny(unused_parens)] #![allow(while_true)] // for rustfix @@ -16,11 +17,11 @@ fn bar(y: bool) -> X { return X { y }; //~ ERROR unnecessary parentheses around `return` value } -pub fn unused_parens_around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type +pub fn around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type panic!() } -pub fn unused_parens_around_block_return() -> u32 { +pub fn around_block_return() -> u32 { let _foo = { 5 //~ ERROR unnecessary parentheses around block return value }; @@ -31,10 +32,90 @@ pub trait Trait { fn test(&self); } -pub fn passes_unused_parens_lint() -> &'static (dyn Trait) { +pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) { panic!() } +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ref() -> &'static dyn Trait { + panic!() +} + +pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) { + panic!() +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ptr() -> *const dyn Trait { + panic!() +} + +pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send { + &|| () +} + +pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) { + &|| () +} + +pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send { + || () +} + +pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_dyn_bound() -> &'static dyn FnOnce() { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_impl_trait_bound() -> impl FnOnce() { + || () +} + +// these parens aren't strictly required but they help disambiguate => no lint +pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound1() -> &'static (dyn Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound2() -> &'static (dyn Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) { + &|| () +} + pub fn parens_with_keyword(e: &[()]) -> i32 { if true {} //~ ERROR unnecessary parentheses around `if` while true {} //~ ERROR unnecessary parentheses around `while` diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs index 02aa78283c7..dccad07311b 100644 --- a/tests/ui/lint/lint-unnecessary-parens.rs +++ b/tests/ui/lint/lint-unnecessary-parens.rs @@ -1,5 +1,6 @@ //@ run-rustfix +#![feature(impl_trait_in_fn_trait_return)] #![deny(unused_parens)] #![allow(while_true)] // for rustfix @@ -16,11 +17,11 @@ fn bar(y: bool) -> X { return (X { y }); //~ ERROR unnecessary parentheses around `return` value } -pub fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type +pub fn around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type panic!() } -pub fn unused_parens_around_block_return() -> u32 { +pub fn around_block_return() -> u32 { let _foo = { (5) //~ ERROR unnecessary parentheses around block return value }; @@ -31,10 +32,90 @@ pub trait Trait { fn test(&self); } -pub fn passes_unused_parens_lint() -> &'static (dyn Trait) { +pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) { panic!() } +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ref() -> &'static (dyn Trait) { + panic!() +} + +pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) { + panic!() +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ptr() -> *const (dyn Trait) { + panic!() +} + +pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { + &|| () +} + +pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) { + &|| () +} + +pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { + || () +} + +pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_impl_trait_bound() -> impl (FnOnce()) { + || () +} + +// these parens aren't strictly required but they help disambiguate => no lint +pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { + &|| () +} + pub fn parens_with_keyword(e: &[()]) -> i32 { if(true) {} //~ ERROR unnecessary parentheses around `if` while(true) {} //~ ERROR unnecessary parentheses around `while` diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr index f2e5debd6e0..a7fc1e89c6c 100644 --- a/tests/ui/lint/lint-unnecessary-parens.stderr +++ b/tests/ui/lint/lint-unnecessary-parens.stderr @@ -1,11 +1,11 @@ error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:13:12 + --> $DIR/lint-unnecessary-parens.rs:14:12 | LL | return (1); | ^ ^ | note: the lint level is defined here - --> $DIR/lint-unnecessary-parens.rs:3:9 + --> $DIR/lint-unnecessary-parens.rs:4:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + return 1; | error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:16:12 + --> $DIR/lint-unnecessary-parens.rs:17:12 | LL | return (X { y }); | ^ ^ @@ -28,19 +28,19 @@ LL + return X { y }; | error: unnecessary parentheses around type - --> $DIR/lint-unnecessary-parens.rs:19:46 + --> $DIR/lint-unnecessary-parens.rs:20:32 | -LL | pub fn unused_parens_around_return_type() -> (u32) { - | ^ ^ +LL | pub fn around_return_type() -> (u32) { + | ^ ^ | help: remove these parentheses | -LL - pub fn unused_parens_around_return_type() -> (u32) { -LL + pub fn unused_parens_around_return_type() -> u32 { +LL - pub fn around_return_type() -> (u32) { +LL + pub fn around_return_type() -> u32 { | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:25:9 + --> $DIR/lint-unnecessary-parens.rs:26:9 | LL | (5) | ^ ^ @@ -52,7 +52,7 @@ LL + 5 | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:27:5 + --> $DIR/lint-unnecessary-parens.rs:28:5 | LL | (5) | ^ ^ @@ -63,8 +63,140 @@ LL - (5) LL + 5 | +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:40:46 + | +LL | pub fn around_single_bound_ref() -> &'static (dyn Trait) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_ref() -> &'static (dyn Trait) { +LL + pub fn around_single_bound_ref() -> &'static dyn Trait { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:49:44 + | +LL | pub fn around_single_bound_ptr() -> *const (dyn Trait) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_ptr() -> *const (dyn Trait) { +LL + pub fn around_single_bound_ptr() -> *const dyn Trait { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:58:72 + | +LL | pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { +LL + pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:71:65 + | +LL | pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { +LL + pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:80:43 + | +LL | pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { +LL + pub fn around_dyn_bound() -> &'static dyn FnOnce() { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:85:42 + | +LL | pub fn around_impl_trait_bound() -> impl (FnOnce()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_impl_trait_bound() -> impl (FnOnce()) { +LL + pub fn around_impl_trait_bound() -> impl FnOnce() { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:95:55 + | +LL | pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { +LL + pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:100:67 + | +LL | pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { +LL + pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:105:49 + | +LL | pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { +LL + pub fn around_regular_bound1() -> &'static (dyn Send + Sync) { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:110:56 + | +LL | pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { +LL + pub fn around_regular_bound2() -> &'static (dyn Send + Sync) { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:115:56 + | +LL | pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { +LL + pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) { + | + error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:39:7 + --> $DIR/lint-unnecessary-parens.rs:120:7 | LL | if(true) {} | ^ ^ @@ -76,7 +208,7 @@ LL + if true {} | error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:40:10 + --> $DIR/lint-unnecessary-parens.rs:121:10 | LL | while(true) {} | ^ ^ @@ -88,7 +220,7 @@ LL + while true {} | error: unnecessary parentheses around `for` iterator expression - --> $DIR/lint-unnecessary-parens.rs:41:13 + --> $DIR/lint-unnecessary-parens.rs:122:13 | LL | for _ in(e) {} | ^ ^ @@ -100,7 +232,7 @@ LL + for _ in e {} | error: unnecessary parentheses around `match` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:42:10 + --> $DIR/lint-unnecessary-parens.rs:123:10 | LL | match(1) { _ => ()} | ^ ^ @@ -112,7 +244,7 @@ LL + match 1 { _ => ()} | error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:43:11 + --> $DIR/lint-unnecessary-parens.rs:124:11 | LL | return(1); | ^ ^ @@ -124,7 +256,7 @@ LL + return 1; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:74:31 + --> $DIR/lint-unnecessary-parens.rs:155:31 | LL | pub const CONST_ITEM: usize = (10); | ^ ^ @@ -136,7 +268,7 @@ LL + pub const CONST_ITEM: usize = 10; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:75:33 + --> $DIR/lint-unnecessary-parens.rs:156:33 | LL | pub static STATIC_ITEM: usize = (10); | ^ ^ @@ -148,7 +280,7 @@ LL + pub static STATIC_ITEM: usize = 10; | error: unnecessary parentheses around function argument - --> $DIR/lint-unnecessary-parens.rs:79:9 + --> $DIR/lint-unnecessary-parens.rs:160:9 | LL | bar((true)); | ^ ^ @@ -160,7 +292,7 @@ LL + bar(true); | error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:81:8 + --> $DIR/lint-unnecessary-parens.rs:162:8 | LL | if (true) {} | ^ ^ @@ -172,7 +304,7 @@ LL + if true {} | error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:82:11 + --> $DIR/lint-unnecessary-parens.rs:163:11 | LL | while (true) {} | ^ ^ @@ -184,7 +316,7 @@ LL + while true {} | error: unnecessary parentheses around `match` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:83:11 + --> $DIR/lint-unnecessary-parens.rs:164:11 | LL | match (true) { | ^ ^ @@ -196,7 +328,7 @@ LL + match true { | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:86:16 + --> $DIR/lint-unnecessary-parens.rs:167:16 | LL | if let 1 = (1) {} | ^ ^ @@ -208,7 +340,7 @@ LL + if let 1 = 1 {} | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:87:19 + --> $DIR/lint-unnecessary-parens.rs:168:19 | LL | while let 1 = (2) {} | ^ ^ @@ -220,7 +352,7 @@ LL + while let 1 = 2 {} | error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:103:24 + --> $DIR/lint-unnecessary-parens.rs:184:24 | LL | X { y: false }.foo((true)); | ^ ^ @@ -232,7 +364,7 @@ LL + X { y: false }.foo(true); | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:105:18 + --> $DIR/lint-unnecessary-parens.rs:186:18 | LL | let mut _a = (0); | ^ ^ @@ -244,7 +376,7 @@ LL + let mut _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:106:10 + --> $DIR/lint-unnecessary-parens.rs:187:10 | LL | _a = (0); | ^ ^ @@ -256,7 +388,7 @@ LL + _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:107:11 + --> $DIR/lint-unnecessary-parens.rs:188:11 | LL | _a += (1); | ^ ^ @@ -268,7 +400,7 @@ LL + _a += 1; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:109:8 + --> $DIR/lint-unnecessary-parens.rs:190:8 | LL | let(mut _a) = 3; | ^ ^ @@ -280,7 +412,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:110:9 + --> $DIR/lint-unnecessary-parens.rs:191:9 | LL | let (mut _a) = 3; | ^ ^ @@ -292,7 +424,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:111:8 + --> $DIR/lint-unnecessary-parens.rs:192:8 | LL | let( mut _a) = 3; | ^^ ^ @@ -304,7 +436,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:113:8 + --> $DIR/lint-unnecessary-parens.rs:194:8 | LL | let(_a) = 3; | ^ ^ @@ -316,7 +448,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:114:9 + --> $DIR/lint-unnecessary-parens.rs:195:9 | LL | let (_a) = 3; | ^ ^ @@ -328,7 +460,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:115:8 + --> $DIR/lint-unnecessary-parens.rs:196:8 | LL | let( _a) = 3; | ^^ ^ @@ -340,7 +472,7 @@ LL + let _a = 3; | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:121:9 + --> $DIR/lint-unnecessary-parens.rs:202:9 | LL | (unit!() - One) | ^ ^ @@ -352,7 +484,7 @@ LL + unit!() - One | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:123:9 + --> $DIR/lint-unnecessary-parens.rs:204:9 | LL | (unit![] - One) | ^ ^ @@ -364,7 +496,7 @@ LL + unit![] - One | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:126:9 + --> $DIR/lint-unnecessary-parens.rs:207:9 | LL | (unit! {} - One) | ^ ^ @@ -376,7 +508,7 @@ LL + unit! {} - One | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:131:14 + --> $DIR/lint-unnecessary-parens.rs:212:14 | LL | let _r = (&x); | ^ ^ @@ -388,7 +520,7 @@ LL + let _r = &x; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:132:14 + --> $DIR/lint-unnecessary-parens.rs:213:14 | LL | let _r = (&mut x); | ^ ^ @@ -399,5 +531,5 @@ LL - let _r = (&mut x); LL + let _r = &mut x; | -error: aborting due to 33 previous errors +error: aborting due to 44 previous errors diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs index 433c2882089..74a0ff83739 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.rs +++ b/tests/ui/lint/unused/issue-105061-should-lint.rs @@ -14,7 +14,7 @@ where trait Hello<T> {} fn with_dyn_bound<T>() where - (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> //~ ERROR unnecessary parentheses around type + dyn Hello<(for<'b> fn(&'b ()))>: Hello<T> //~ ERROR unnecessary parentheses around type {} fn main() { diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr index e591f1ffb6b..ae69f018eae 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.stderr +++ b/tests/ui/lint/unused/issue-105061-should-lint.stderr @@ -17,15 +17,15 @@ LL + for<'b> for<'a> fn(Inv<'a>): Trait<'b>, | error: unnecessary parentheses around type - --> $DIR/issue-105061-should-lint.rs:17:16 + --> $DIR/issue-105061-should-lint.rs:17:15 | -LL | (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> - | ^ ^ +LL | dyn Hello<(for<'b> fn(&'b ()))>: Hello<T> + | ^ ^ | help: remove these parentheses | -LL - (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> -LL + (dyn Hello<for<'b> fn(&'b ())>): Hello<T> +LL - dyn Hello<(for<'b> fn(&'b ()))>: Hello<T> +LL + dyn Hello<for<'b> fn(&'b ())>: Hello<T> | error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed new file mode 100644 index 00000000000..f95418868e1 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed @@ -0,0 +1,27 @@ +//@ revisions: edition2015 edition2018 +//@[edition2015] check-pass +//@[edition2015] edition: 2015 +//@[edition2018] run-rustfix +//@[edition2018] edition: 2018 + +#![deny(unused_parens)] + +#[allow(unused)] +macro_rules! edition2015_only { + () => { + mod dyn { + pub type IsAContextualKeywordIn2015 = (); + } + + pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015; + } +} + +#[cfg(edition2015)] +edition2015_only!(); + +// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015 +//[edition2018]~v ERROR unnecessary parentheses around type +pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>; + +fn main() {} diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr new file mode 100644 index 00000000000..aed8cec68e8 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr @@ -0,0 +1,19 @@ +error: unnecessary parentheses around type + --> $DIR/unused-parens-trait-obj.rs:25:51 + | +LL | pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-trait-obj.rs:7:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>; +LL + pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.rs b/tests/ui/lint/unused/unused-parens-trait-obj.rs new file mode 100644 index 00000000000..2192baa2e02 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.rs @@ -0,0 +1,27 @@ +//@ revisions: edition2015 edition2018 +//@[edition2015] check-pass +//@[edition2015] edition: 2015 +//@[edition2018] run-rustfix +//@[edition2018] edition: 2018 + +#![deny(unused_parens)] + +#[allow(unused)] +macro_rules! edition2015_only { + () => { + mod dyn { + pub type IsAContextualKeywordIn2015 = (); + } + + pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015; + } +} + +#[cfg(edition2015)] +edition2015_only!(); + +// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015 +//[edition2018]~v ERROR unnecessary parentheses around type +pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>; + +fn main() {} diff --git a/tests/ui/loop-match/invalid.rs b/tests/ui/loop-match/invalid.rs index 2ddc19f4fc6..0c47b1e0057 100644 --- a/tests/ui/loop-match/invalid.rs +++ b/tests/ui/loop-match/invalid.rs @@ -159,3 +159,34 @@ fn arm_has_guard(cond: bool) { } } } + +fn non_exhaustive() { + let mut state = State::A; + #[loop_match] + loop { + state = 'blk: { + match state { + //~^ ERROR non-exhaustive patterns: `State::B` and `State::C` not covered + State::A => State::B, + } + } + } +} + +fn invalid_range_pattern(state: f32) { + #[loop_match] + loop { + state = 'blk: { + match state { + 1.0 => { + #[const_continue] + break 'blk 2.5; + } + 4.0..3.0 => { + //~^ ERROR lower range bound must be less than upper + todo!() + } + } + } + } +} diff --git a/tests/ui/loop-match/invalid.stderr b/tests/ui/loop-match/invalid.stderr index 51fdd024c6f..70f246caa9c 100644 --- a/tests/ui/loop-match/invalid.stderr +++ b/tests/ui/loop-match/invalid.stderr @@ -86,6 +86,36 @@ error: match arms that are part of a `#[loop_match]` cannot have guards LL | State::B if cond => break 'a, | ^^^^ -error: aborting due to 12 previous errors +error[E0004]: non-exhaustive patterns: `State::B` and `State::C` not covered + --> $DIR/invalid.rs:168:19 + | +LL | match state { + | ^^^^^ patterns `State::B` and `State::C` not covered + | +note: `State` defined here + --> $DIR/invalid.rs:7:6 + | +LL | enum State { + | ^^^^^ +LL | A, +LL | B, + | - not covered +LL | C, + | - not covered + = note: the matched value is of type `State` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ State::A => State::B, +LL ~ State::B | State::C => todo!(), + | + +error[E0579]: lower range bound must be less than upper + --> $DIR/invalid.rs:185:17 + | +LL | 4.0..3.0 => { + | ^^^^^^^^ + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0004, E0308, E0579. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/macros/missing-semi.stderr b/tests/ui/macros/missing-semi.stderr index 0a7afe50059..c2e12adbb4b 100644 --- a/tests/ui/macros/missing-semi.stderr +++ b/tests/ui/macros/missing-semi.stderr @@ -1,8 +1,10 @@ error: expected `;`, found `(` --> $DIR/missing-semi.rs:6:5 | +LL | } + | - expected `;` LL | () => { - | ^ no rules expected this token in macro call + | ^ unexpected token error: aborting due to 1 previous error diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index c858051a7eb..fa06da5cbfb 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ edition:2021 +//@ edition:2024 //@ compile-flags: --test #![allow(incomplete_features)] @@ -10,7 +10,6 @@ #![feature(decl_macro)] #![feature(explicit_tail_calls)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(more_qualified_paths)] #![feature(never_patterns)] #![feature(trait_alias)] diff --git a/tests/ui/mir/enum/negative_discr_break.rs b/tests/ui/mir/enum/negative_discr_break.rs new file mode 100644 index 00000000000..fa1284f72a0 --- /dev/null +++ b/tests/ui/mir/enum/negative_discr_break.rs @@ -0,0 +1,14 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: trying to construct an enum from an invalid value 0xfd + +#[allow(dead_code)] +enum Foo { + A = -2, + B = -1, + C = 1, +} + +fn main() { + let _val: Foo = unsafe { std::mem::transmute::<i8, Foo>(-3) }; +} diff --git a/tests/ui/mir/enum/negative_discr_ok.rs b/tests/ui/mir/enum/negative_discr_ok.rs new file mode 100644 index 00000000000..5c15b33fa84 --- /dev/null +++ b/tests/ui/mir/enum/negative_discr_ok.rs @@ -0,0 +1,53 @@ +//@ run-pass +//@ compile-flags: -C debug-assertions + +#[allow(dead_code)] +#[derive(Debug, PartialEq)] +enum Foo { + A = -12121, + B = -2, + C = -1, + D = 1, + E = 2, + F = 12121, +} + +#[allow(dead_code)] +#[repr(i64)] +#[derive(Debug, PartialEq)] +enum Bar { + A = i64::MIN, + B = -2, + C = -1, + D = 1, + E = 2, + F = i64::MAX, +} + +fn main() { + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-12121) }; + assert_eq!(val, Foo::A); + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-2) }; + assert_eq!(val, Foo::B); + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-1) }; + assert_eq!(val, Foo::C); + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(1) }; + assert_eq!(val, Foo::D); + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(2) }; + assert_eq!(val, Foo::E); + let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(12121) }; + assert_eq!(val, Foo::F); + + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(i64::MIN) }; + assert_eq!(val, Bar::A); + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(-2) }; + assert_eq!(val, Bar::B); + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(-1) }; + assert_eq!(val, Bar::C); + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(1) }; + assert_eq!(val, Bar::D); + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(2) }; + assert_eq!(val, Bar::E); + let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(i64::MAX) }; + assert_eq!(val, Bar::F); +} diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs index 4794f3427dd..8a54f21b57f 100644 --- a/tests/ui/mir/mir_let_chains_drop_order.rs +++ b/tests/ui/mir/mir_let_chains_drop_order.rs @@ -1,12 +1,9 @@ //@ run-pass //@ needs-unwind -//@ revisions: edition2021 edition2024 -//@ [edition2021] edition: 2021 -//@ [edition2024] edition: 2024 +//@ edition: 2024 // See `mir_drop_order.rs` for more information -#![cfg_attr(edition2021, feature(let_chains))] #![allow(irrefutable_let_patterns)] use std::cell::RefCell; @@ -64,9 +61,6 @@ fn main() { d(10, None) }, ); - #[cfg(edition2021)] - assert_eq!(get(), vec![8, 7, 1, 3, 2]); - #[cfg(edition2024)] assert_eq!(get(), vec![3, 2, 8, 7, 1]); } assert_eq!(get(), vec![0, 4, 6, 9, 5]); @@ -101,8 +95,5 @@ fn main() { panic::panic_any(InjectedFailure), ); }); - #[cfg(edition2021)] - assert_eq!(get(), vec![20, 17, 15, 11, 19, 18, 16, 12, 14, 13]); - #[cfg(edition2024)] assert_eq!(get(), vec![14, 13, 19, 18, 20, 17, 15, 11, 16, 12]); } diff --git a/tests/ui/parser/issues/issue-7970b.rs b/tests/ui/parser/issues/issue-7970b.rs index 1c4abce3959..ae06aff7cef 100644 --- a/tests/ui/parser/issues/issue-7970b.rs +++ b/tests/ui/parser/issues/issue-7970b.rs @@ -1,4 +1,4 @@ fn main() {} macro_rules! test {} -//~^ ERROR unexpected end of macro invocation +//~^ ERROR macros must contain at least one rule diff --git a/tests/ui/parser/issues/issue-7970b.stderr b/tests/ui/parser/issues/issue-7970b.stderr index b23b09e752c..4715eb07c6d 100644 --- a/tests/ui/parser/issues/issue-7970b.stderr +++ b/tests/ui/parser/issues/issue-7970b.stderr @@ -1,8 +1,8 @@ -error: unexpected end of macro invocation +error: macros must contain at least one rule --> $DIR/issue-7970b.rs:3:1 | LL | macro_rules! test {} - | ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/parser/macros-no-semicolon-items.rs b/tests/ui/parser/macros-no-semicolon-items.rs index 3afc275d61a..86889279cea 100644 --- a/tests/ui/parser/macros-no-semicolon-items.rs +++ b/tests/ui/parser/macros-no-semicolon-items.rs @@ -1,5 +1,5 @@ macro_rules! foo() //~ ERROR semicolon - //~| ERROR unexpected end of macro + //~| ERROR macros must contain at least one rule macro_rules! bar { ($($tokens:tt)*) => {} diff --git a/tests/ui/parser/macros-no-semicolon-items.stderr b/tests/ui/parser/macros-no-semicolon-items.stderr index 07fa2439df5..f8f3ed83688 100644 --- a/tests/ui/parser/macros-no-semicolon-items.stderr +++ b/tests/ui/parser/macros-no-semicolon-items.stderr @@ -38,11 +38,11 @@ help: add a semicolon LL | ); | + -error: unexpected end of macro invocation +error: macros must contain at least one rule --> $DIR/macros-no-semicolon-items.rs:1:1 | LL | macro_rules! foo() - | ^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs index 16737e0a894..883ce4333ca 100644 --- a/tests/ui/pattern/usefulness/conflicting_bindings.rs +++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs @@ -1,4 +1,6 @@ -#![feature(if_let_guard, let_chains)] +//@ edition: 2024 + +#![feature(if_let_guard)] fn main() { let mut x = Some(String::new()); diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr index 6f6504e6f64..7ab3393c8d1 100644 --- a/tests/ui/pattern/usefulness/conflicting_bindings.stderr +++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:5:9 + --> $DIR/conflicting_bindings.rs:7:9 | LL | let ref mut y @ ref mut z = x; | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -7,7 +7,7 @@ LL | let ref mut y @ ref mut z = x; | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:7:14 + --> $DIR/conflicting_bindings.rs:9:14 | LL | let Some(ref mut y @ ref mut z) = x else { return }; | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -15,7 +15,7 @@ LL | let Some(ref mut y @ ref mut z) = x else { return }; | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:9:17 + --> $DIR/conflicting_bindings.rs:11:17 | LL | if let Some(ref mut y @ ref mut z) = x {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -23,7 +23,7 @@ LL | if let Some(ref mut y @ ref mut z) = x {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:11:17 + --> $DIR/conflicting_bindings.rs:13:17 | LL | if let Some(ref mut y @ ref mut z) = x && true {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -31,7 +31,7 @@ LL | if let Some(ref mut y @ ref mut z) = x && true {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:13:43 + --> $DIR/conflicting_bindings.rs:15:43 | LL | if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -39,7 +39,7 @@ LL | if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && tru | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:15:20 + --> $DIR/conflicting_bindings.rs:17:20 | LL | while let Some(ref mut y @ ref mut z) = x {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -47,7 +47,7 @@ LL | while let Some(ref mut y @ ref mut z) = x {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:17:20 + --> $DIR/conflicting_bindings.rs:19:20 | LL | while let Some(ref mut y @ ref mut z) = x && true {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -55,7 +55,7 @@ LL | while let Some(ref mut y @ ref mut z) = x && true {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:20:9 + --> $DIR/conflicting_bindings.rs:22:9 | LL | ref mut y @ ref mut z => {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -63,7 +63,7 @@ LL | ref mut y @ ref mut z => {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:23:24 + --> $DIR/conflicting_bindings.rs:25:24 | LL | () if let Some(ref mut y @ ref mut z) = x => {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs new file mode 100644 index 00000000000..4d2eac2ea2d --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs @@ -0,0 +1,57 @@ +// Ensure that temporaries in if-let guards live for the arm +// regression test for #118593 + +//@ check-pass +//@ edition: 2024 + +#![feature(if_let_guard)] + +fn get_temp() -> Option<String> { + None +} + +fn let_let_chain_guard(num: u8) { + match num { + 5 | 6 + if let Some(ref a) = get_temp() + && let Some(ref b) = get_temp() => + { + let _x = a; + let _y = b; + } + _ => {} + } + match num { + 7 | 8 + if let Some(ref mut c) = get_temp() + && let Some(ref mut d) = get_temp() => + { + let _w = c; + let _z = d; + } + _ => {} + } +} + +fn let_cond_chain_guard(num: u8) { + match num { + 9 | 10 + if let Some(ref a) = get_temp() + && true => + { + let _x = a; + } + _ => {} + } + match num { + 11 | 12 + if let Some(ref mut b) = get_temp() + && true => + { + let _w = b; + } + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs index 0578b827a47..59e33bb6af8 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs @@ -4,7 +4,6 @@ //@ check-pass #![feature(if_let_guard)] -#![feature(let_chains)] fn get_temp() -> Option<String> { None @@ -25,48 +24,4 @@ fn let_guard(num: u8) { } } -fn let_let_chain_guard(num: u8) { - match num { - 5 | 6 - if let Some(ref a) = get_temp() - && let Some(ref b) = get_temp() => - { - let _x = a; - let _y = b; - } - _ => {} - } - match num { - 7 | 8 - if let Some(ref mut c) = get_temp() - && let Some(ref mut d) = get_temp() => - { - let _w = c; - let _z = d; - } - _ => {} - } -} - -fn let_cond_chain_guard(num: u8) { - match num { - 9 | 10 - if let Some(ref a) = get_temp() - && true => - { - let _x = a; - } - _ => {} - } - match num { - 11 | 12 - if let Some(ref mut b) = get_temp() - && true => - { - let _w = b; - } - _ => {} - } -} - fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs index e836b0b88ff..294a0d02770 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(if_let_guard)] -#![feature(let_chains)] macro_rules! m { (pattern $i:ident) => { Some($i) }; diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs index 56a6fb5bfa3..47cc7a64bd1 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs @@ -3,7 +3,6 @@ //@run-pass #![feature(if_let_guard)] -#![feature(let_chains)] #![allow(irrefutable_let_patterns)] fn lhs_let(opt: Option<bool>) { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr index dda09de4c53..15e7be8c65f 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr @@ -1,239 +1,263 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:48:8 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:48:21 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:48 + --> $DIR/disallowed-positions.rs:48:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:61 + --> $DIR/disallowed-positions.rs:48:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:74:11 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:74:24 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:51 + --> $DIR/disallowed-positions.rs:74:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:64 + --> $DIR/disallowed-positions.rs:74:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +265,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:105:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +273,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:108:9 + --> $DIR/disallowed-positions.rs:107:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +281,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:110:9 + --> $DIR/disallowed-positions.rs:109:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +289,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:9 + --> $DIR/disallowed-positions.rs:117:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,13 +297,13 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:121:13 + --> $DIR/disallowed-positions.rs:120:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:17 + --> $DIR/disallowed-positions.rs:122:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -287,7 +311,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:125:25 + --> $DIR/disallowed-positions.rs:124:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -295,7 +319,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:25 + --> $DIR/disallowed-positions.rs:126:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -303,7 +327,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:131:12 + --> $DIR/disallowed-positions.rs:130:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -311,7 +335,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:15 + --> $DIR/disallowed-positions.rs:133:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -319,7 +343,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:137:11 + --> $DIR/disallowed-positions.rs:136:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -327,7 +351,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:9 + --> $DIR/disallowed-positions.rs:138:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -335,7 +359,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:143:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -343,7 +367,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:146:8 + --> $DIR/disallowed-positions.rs:145:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -351,7 +375,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:152:8 + --> $DIR/disallowed-positions.rs:151:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -359,7 +383,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:8 + --> $DIR/disallowed-positions.rs:157:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +391,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:162:19 + --> $DIR/disallowed-positions.rs:161:19 | LL | if let true = let true = true {} | ^^^ @@ -375,7 +399,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:165:15 + --> $DIR/disallowed-positions.rs:164:15 | LL | if return let 0 = 0 {} | ^^^ @@ -383,7 +407,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:21 + --> $DIR/disallowed-positions.rs:167:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -391,7 +415,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:171:15 + --> $DIR/disallowed-positions.rs:170:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -399,7 +423,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:174:9 + --> $DIR/disallowed-positions.rs:173:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -407,7 +431,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:9 + --> $DIR/disallowed-positions.rs:176:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -415,7 +439,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:13 + --> $DIR/disallowed-positions.rs:180:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -423,7 +447,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:12 + --> $DIR/disallowed-positions.rs:184:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -431,7 +455,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:188:9 + --> $DIR/disallowed-positions.rs:187:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -439,7 +463,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -447,7 +471,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:196:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -455,7 +479,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:198:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -463,7 +487,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:201:12 + --> $DIR/disallowed-positions.rs:200:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -471,7 +495,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:209:12 + --> $DIR/disallowed-positions.rs:208:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -479,13 +503,13 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:212:16 + --> $DIR/disallowed-positions.rs:211:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:20 + --> $DIR/disallowed-positions.rs:213:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -493,7 +517,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:216:28 + --> $DIR/disallowed-positions.rs:215:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -501,7 +525,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:28 + --> $DIR/disallowed-positions.rs:217:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -509,7 +533,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:15 + --> $DIR/disallowed-positions.rs:221:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -517,7 +541,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:225:18 + --> $DIR/disallowed-positions.rs:224:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -525,7 +549,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:228:14 + --> $DIR/disallowed-positions.rs:227:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -533,7 +557,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:12 + --> $DIR/disallowed-positions.rs:229:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -541,7 +565,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:234:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -549,7 +573,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:237:11 + --> $DIR/disallowed-positions.rs:236:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -557,7 +581,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:243:11 + --> $DIR/disallowed-positions.rs:242:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -565,7 +589,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:11 + --> $DIR/disallowed-positions.rs:248:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -573,7 +597,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:253:22 + --> $DIR/disallowed-positions.rs:252:22 | LL | while let true = let true = true {} | ^^^ @@ -581,7 +605,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:18 + --> $DIR/disallowed-positions.rs:255:18 | LL | while return let 0 = 0 {} | ^^^ @@ -589,7 +613,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:39 + --> $DIR/disallowed-positions.rs:258:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -597,7 +621,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:262:18 + --> $DIR/disallowed-positions.rs:261:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -605,7 +629,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:265:12 + --> $DIR/disallowed-positions.rs:264:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -613,7 +637,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:12 + --> $DIR/disallowed-positions.rs:267:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -621,7 +645,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:16 + --> $DIR/disallowed-positions.rs:271:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -629,7 +653,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:276:15 + --> $DIR/disallowed-positions.rs:275:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -637,7 +661,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:279:12 + --> $DIR/disallowed-positions.rs:278:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -645,7 +669,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:296:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | &let 0 = 0; | ^^^ @@ -653,7 +677,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:298:6 | LL | !let 0 = 0; | ^^^ @@ -661,7 +685,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:6 + --> $DIR/disallowed-positions.rs:300:6 | LL | *let 0 = 0; | ^^^ @@ -669,7 +693,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:303:6 + --> $DIR/disallowed-positions.rs:302:6 | LL | -let 0 = 0; | ^^^ @@ -677,7 +701,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:305:13 + --> $DIR/disallowed-positions.rs:304:13 | LL | let _ = let _ = 3; | ^^^ @@ -685,7 +709,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:313:6 + --> $DIR/disallowed-positions.rs:312:6 | LL | (let 0 = 0)?; | ^^^ @@ -693,7 +717,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:13 + --> $DIR/disallowed-positions.rs:315:13 | LL | true || let 0 = 0; | ^^^ @@ -701,7 +725,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:318:14 + --> $DIR/disallowed-positions.rs:317:14 | LL | (true || let 0 = 0); | ^^^ @@ -709,7 +733,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:22 + --> $DIR/disallowed-positions.rs:319:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -717,7 +741,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:324:9 + --> $DIR/disallowed-positions.rs:323:9 | LL | x = let 0 = 0; | ^^^ @@ -725,7 +749,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:12 + --> $DIR/disallowed-positions.rs:326:12 | LL | true..(let 0 = 0); | ^^^ @@ -733,7 +757,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:329:8 + --> $DIR/disallowed-positions.rs:328:8 | LL | ..(let 0 = 0); | ^^^ @@ -741,7 +765,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:331:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let 0 = 0)..; | ^^^ @@ -749,7 +773,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:333:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -757,7 +781,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:6 + --> $DIR/disallowed-positions.rs:337:6 | LL | (let true = let true = true); | ^^^ @@ -765,7 +789,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:17 + --> $DIR/disallowed-positions.rs:337:17 | LL | (let true = let true = true); | ^^^ @@ -773,7 +797,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:25 + --> $DIR/disallowed-positions.rs:343:25 | LL | let x = true && let y = 1; | ^^^ @@ -781,7 +805,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:350:19 + --> $DIR/disallowed-positions.rs:349:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -789,7 +813,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:6 + --> $DIR/disallowed-positions.rs:354:6 | LL | &let 0 = 0 | ^^^ @@ -797,7 +821,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:366:17 + --> $DIR/disallowed-positions.rs:365:17 | LL | true && let 1 = 1 | ^^^ @@ -805,7 +829,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:371:17 + --> $DIR/disallowed-positions.rs:370:17 | LL | true && let 1 = 1 | ^^^ @@ -813,7 +837,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:376:17 + --> $DIR/disallowed-positions.rs:375:17 | LL | true && let 1 = 1 | ^^^ @@ -821,7 +845,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:387:17 + --> $DIR/disallowed-positions.rs:386:17 | LL | true && let 1 = 1 | ^^^ @@ -829,7 +853,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:387:9 + --> $DIR/disallowed-positions.rs:386:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -840,124 +864,154 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:407:8 + | +LL | if let Some(a) = opt && (true && true) { + | ^^^^^^^^^^^^^^^^^ + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:423:28 + | +LL | if (true && (true)) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:426:18 + | +LL | if (true) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:429:16 + | +LL | if true && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/disallowed-positions.rs:434:8 + | +LL | if let true = (true && fun()) && (true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:440:22 + --> $DIR/disallowed-positions.rs:439:22 | LL | let x = (true && let y = 1); | ^^^ @@ -965,7 +1019,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:445:20 + --> $DIR/disallowed-positions.rs:444:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -973,7 +1027,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -981,7 +1035,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -990,7 +1044,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -999,7 +1053,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1007,7 +1061,7 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1016,7 +1070,7 @@ LL | use_expr!((let 0 = 1)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1024,98 +1078,8 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:49:8 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:49:21 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:75:11 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:75:24 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:408:8 - | -LL | if let Some(a) = opt && (true && true) { - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:424:28 - | -LL | if (true && (true)) && let Some(a) = opt { - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:427:18 - | -LL | if (true) && let Some(a) = opt { - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:430:16 - | -LL | if true && let Some(a) = opt { - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:435:8 - | -LL | if let true = (true && fun()) && (true) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:134:8 + --> $DIR/disallowed-positions.rs:133:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` @@ -1124,7 +1088,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:143:12 + --> $DIR/disallowed-positions.rs:142:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1135,7 +1099,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:146:12 + --> $DIR/disallowed-positions.rs:145:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1146,7 +1110,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:152:12 + --> $DIR/disallowed-positions.rs:151:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1157,7 +1121,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:158:12 + --> $DIR/disallowed-positions.rs:157:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1168,7 +1132,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:114:20 + --> $DIR/disallowed-positions.rs:113:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1176,7 +1140,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:225:11 + --> $DIR/disallowed-positions.rs:224:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` @@ -1185,7 +1149,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:234:15 + --> $DIR/disallowed-positions.rs:233:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1196,7 +1160,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:237:15 + --> $DIR/disallowed-positions.rs:236:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1207,7 +1171,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:243:15 + --> $DIR/disallowed-positions.rs:242:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1218,7 +1182,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:249:15 + --> $DIR/disallowed-positions.rs:248:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1229,7 +1193,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:205:23 + --> $DIR/disallowed-positions.rs:204:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1237,7 +1201,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:334:10 + --> $DIR/disallowed-positions.rs:333:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1248,7 +1212,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:309:17 + --> $DIR/disallowed-positions.rs:308:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1257,5 +1221,5 @@ LL | let 0 = 0?; error: aborting due to 134 previous errors -Some errors have detailed explanations: E0277, E0308, E0658. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr index 141a6d255d0..20af65cf89a 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:48 + --> $DIR/disallowed-positions.rs:48:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:61 + --> $DIR/disallowed-positions.rs:48:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:51 + --> $DIR/disallowed-positions.rs:74:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:64 + --> $DIR/disallowed-positions.rs:74:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:105:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:108:9 + --> $DIR/disallowed-positions.rs:107:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:110:9 + --> $DIR/disallowed-positions.rs:109:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:9 + --> $DIR/disallowed-positions.rs:117:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,13 +273,13 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:121:13 + --> $DIR/disallowed-positions.rs:120:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:17 + --> $DIR/disallowed-positions.rs:122:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:125:25 + --> $DIR/disallowed-positions.rs:124:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -295,7 +295,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:25 + --> $DIR/disallowed-positions.rs:126:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -303,7 +303,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:131:12 + --> $DIR/disallowed-positions.rs:130:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -311,7 +311,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:15 + --> $DIR/disallowed-positions.rs:133:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -319,7 +319,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:137:11 + --> $DIR/disallowed-positions.rs:136:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -327,7 +327,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:9 + --> $DIR/disallowed-positions.rs:138:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -335,7 +335,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:143:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -343,7 +343,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:146:8 + --> $DIR/disallowed-positions.rs:145:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:152:8 + --> $DIR/disallowed-positions.rs:151:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -359,7 +359,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:8 + --> $DIR/disallowed-positions.rs:157:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:162:19 + --> $DIR/disallowed-positions.rs:161:19 | LL | if let true = let true = true {} | ^^^ @@ -375,7 +375,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:165:15 + --> $DIR/disallowed-positions.rs:164:15 | LL | if return let 0 = 0 {} | ^^^ @@ -383,7 +383,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:21 + --> $DIR/disallowed-positions.rs:167:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -391,7 +391,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:171:15 + --> $DIR/disallowed-positions.rs:170:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -399,7 +399,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:174:9 + --> $DIR/disallowed-positions.rs:173:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -407,7 +407,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:9 + --> $DIR/disallowed-positions.rs:176:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -415,7 +415,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:13 + --> $DIR/disallowed-positions.rs:180:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -423,7 +423,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:12 + --> $DIR/disallowed-positions.rs:184:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -431,7 +431,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:188:9 + --> $DIR/disallowed-positions.rs:187:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -439,7 +439,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -447,7 +447,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:196:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -455,7 +455,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:198:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -463,7 +463,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:201:12 + --> $DIR/disallowed-positions.rs:200:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -471,7 +471,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:209:12 + --> $DIR/disallowed-positions.rs:208:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -479,13 +479,13 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:212:16 + --> $DIR/disallowed-positions.rs:211:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:20 + --> $DIR/disallowed-positions.rs:213:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -493,7 +493,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:216:28 + --> $DIR/disallowed-positions.rs:215:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -501,7 +501,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:28 + --> $DIR/disallowed-positions.rs:217:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -509,7 +509,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:15 + --> $DIR/disallowed-positions.rs:221:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -517,7 +517,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:225:18 + --> $DIR/disallowed-positions.rs:224:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -525,7 +525,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:228:14 + --> $DIR/disallowed-positions.rs:227:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -533,7 +533,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:12 + --> $DIR/disallowed-positions.rs:229:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -541,7 +541,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:234:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -549,7 +549,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:237:11 + --> $DIR/disallowed-positions.rs:236:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -557,7 +557,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:243:11 + --> $DIR/disallowed-positions.rs:242:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -565,7 +565,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:11 + --> $DIR/disallowed-positions.rs:248:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -573,7 +573,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:253:22 + --> $DIR/disallowed-positions.rs:252:22 | LL | while let true = let true = true {} | ^^^ @@ -581,7 +581,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:18 + --> $DIR/disallowed-positions.rs:255:18 | LL | while return let 0 = 0 {} | ^^^ @@ -589,7 +589,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:39 + --> $DIR/disallowed-positions.rs:258:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -597,7 +597,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:262:18 + --> $DIR/disallowed-positions.rs:261:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -605,7 +605,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:265:12 + --> $DIR/disallowed-positions.rs:264:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -613,7 +613,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:12 + --> $DIR/disallowed-positions.rs:267:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -621,7 +621,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:16 + --> $DIR/disallowed-positions.rs:271:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -629,7 +629,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:276:15 + --> $DIR/disallowed-positions.rs:275:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -637,7 +637,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:279:12 + --> $DIR/disallowed-positions.rs:278:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -645,7 +645,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:296:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | &let 0 = 0; | ^^^ @@ -653,7 +653,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:298:6 | LL | !let 0 = 0; | ^^^ @@ -661,7 +661,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:6 + --> $DIR/disallowed-positions.rs:300:6 | LL | *let 0 = 0; | ^^^ @@ -669,7 +669,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:303:6 + --> $DIR/disallowed-positions.rs:302:6 | LL | -let 0 = 0; | ^^^ @@ -677,7 +677,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:305:13 + --> $DIR/disallowed-positions.rs:304:13 | LL | let _ = let _ = 3; | ^^^ @@ -685,7 +685,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:313:6 + --> $DIR/disallowed-positions.rs:312:6 | LL | (let 0 = 0)?; | ^^^ @@ -693,7 +693,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:13 + --> $DIR/disallowed-positions.rs:315:13 | LL | true || let 0 = 0; | ^^^ @@ -701,7 +701,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:318:14 + --> $DIR/disallowed-positions.rs:317:14 | LL | (true || let 0 = 0); | ^^^ @@ -709,7 +709,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:22 + --> $DIR/disallowed-positions.rs:319:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -717,7 +717,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:324:9 + --> $DIR/disallowed-positions.rs:323:9 | LL | x = let 0 = 0; | ^^^ @@ -725,7 +725,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:12 + --> $DIR/disallowed-positions.rs:326:12 | LL | true..(let 0 = 0); | ^^^ @@ -733,7 +733,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:329:8 + --> $DIR/disallowed-positions.rs:328:8 | LL | ..(let 0 = 0); | ^^^ @@ -741,7 +741,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:331:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let 0 = 0)..; | ^^^ @@ -749,7 +749,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:333:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -757,7 +757,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:6 + --> $DIR/disallowed-positions.rs:337:6 | LL | (let true = let true = true); | ^^^ @@ -765,7 +765,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:17 + --> $DIR/disallowed-positions.rs:337:17 | LL | (let true = let true = true); | ^^^ @@ -773,7 +773,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:25 + --> $DIR/disallowed-positions.rs:343:25 | LL | let x = true && let y = 1; | ^^^ @@ -781,7 +781,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:350:19 + --> $DIR/disallowed-positions.rs:349:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -789,7 +789,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:6 + --> $DIR/disallowed-positions.rs:354:6 | LL | &let 0 = 0 | ^^^ @@ -797,7 +797,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:366:17 + --> $DIR/disallowed-positions.rs:365:17 | LL | true && let 1 = 1 | ^^^ @@ -805,7 +805,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:371:17 + --> $DIR/disallowed-positions.rs:370:17 | LL | true && let 1 = 1 | ^^^ @@ -813,7 +813,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:376:17 + --> $DIR/disallowed-positions.rs:375:17 | LL | true && let 1 = 1 | ^^^ @@ -821,7 +821,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:387:17 + --> $DIR/disallowed-positions.rs:386:17 | LL | true && let 1 = 1 | ^^^ @@ -829,7 +829,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:387:9 + --> $DIR/disallowed-positions.rs:386:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -840,124 +840,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:440:22 + --> $DIR/disallowed-positions.rs:439:22 | LL | let x = (true && let y = 1); | ^^^ @@ -965,7 +965,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:445:20 + --> $DIR/disallowed-positions.rs:444:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -973,7 +973,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -981,7 +981,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -990,7 +990,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -999,7 +999,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1007,7 +1007,7 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1016,7 +1016,7 @@ LL | use_expr!((let 0 = 1)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:16 + --> $DIR/disallowed-positions.rs:94:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -1025,7 +1025,7 @@ LL | use_expr!((let 0 = 1)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:134:8 + --> $DIR/disallowed-positions.rs:133:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` @@ -1034,7 +1034,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:143:12 + --> $DIR/disallowed-positions.rs:142:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1045,7 +1045,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:146:12 + --> $DIR/disallowed-positions.rs:145:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1056,7 +1056,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:152:12 + --> $DIR/disallowed-positions.rs:151:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1067,7 +1067,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:158:12 + --> $DIR/disallowed-positions.rs:157:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1078,7 +1078,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:114:20 + --> $DIR/disallowed-positions.rs:113:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1086,7 +1086,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:225:11 + --> $DIR/disallowed-positions.rs:224:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` @@ -1095,7 +1095,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:234:15 + --> $DIR/disallowed-positions.rs:233:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1106,7 +1106,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:237:15 + --> $DIR/disallowed-positions.rs:236:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1117,7 +1117,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:243:15 + --> $DIR/disallowed-positions.rs:242:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1128,7 +1128,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:249:15 + --> $DIR/disallowed-positions.rs:248:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1139,7 +1139,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:205:23 + --> $DIR/disallowed-positions.rs:204:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1147,7 +1147,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:334:10 + --> $DIR/disallowed-positions.rs:333:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1158,7 +1158,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:309:17 + --> $DIR/disallowed-positions.rs:308:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr index 5b53691cbf5..f69c18ff0d9 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:36:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:39:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:42:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:48 + --> $DIR/disallowed-positions.rs:48:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:49:61 + --> $DIR/disallowed-positions.rs:48:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:49:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:59:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:62:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:71:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:51 + --> $DIR/disallowed-positions.rs:74:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:75:64 + --> $DIR/disallowed-positions.rs:74:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:75:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:9 + --> $DIR/disallowed-positions.rs:105:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:108:9 + --> $DIR/disallowed-positions.rs:107:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:110:9 + --> $DIR/disallowed-positions.rs:109:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:9 + --> $DIR/disallowed-positions.rs:117:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,13 +273,13 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:121:13 + --> $DIR/disallowed-positions.rs:120:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:123:17 + --> $DIR/disallowed-positions.rs:122:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:125:25 + --> $DIR/disallowed-positions.rs:124:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -295,7 +295,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:127:25 + --> $DIR/disallowed-positions.rs:126:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -303,7 +303,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:131:12 + --> $DIR/disallowed-positions.rs:130:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -311,7 +311,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:15 + --> $DIR/disallowed-positions.rs:133:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -319,7 +319,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:137:11 + --> $DIR/disallowed-positions.rs:136:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -327,7 +327,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:139:9 + --> $DIR/disallowed-positions.rs:138:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -335,7 +335,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:143:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -343,7 +343,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:146:8 + --> $DIR/disallowed-positions.rs:145:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:152:8 + --> $DIR/disallowed-positions.rs:151:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -359,7 +359,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:158:8 + --> $DIR/disallowed-positions.rs:157:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:162:19 + --> $DIR/disallowed-positions.rs:161:19 | LL | if let true = let true = true {} | ^^^ @@ -375,7 +375,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:165:15 + --> $DIR/disallowed-positions.rs:164:15 | LL | if return let 0 = 0 {} | ^^^ @@ -383,7 +383,7 @@ LL | if return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:21 + --> $DIR/disallowed-positions.rs:167:21 | LL | loop { if break let 0 = 0 {} } | ^^^ @@ -391,7 +391,7 @@ LL | loop { if break let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:171:15 + --> $DIR/disallowed-positions.rs:170:15 | LL | if (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -399,7 +399,7 @@ LL | if (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:174:9 + --> $DIR/disallowed-positions.rs:173:9 | LL | if (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -407,7 +407,7 @@ LL | if (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:177:9 + --> $DIR/disallowed-positions.rs:176:9 | LL | if (let 0 = 0,) {} | ^^^^^^^^^ @@ -415,7 +415,7 @@ LL | if (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:13 + --> $DIR/disallowed-positions.rs:180:13 | LL | if (let 0 = 0).await {} | ^^^^^^^^^ @@ -423,7 +423,7 @@ LL | if (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:12 + --> $DIR/disallowed-positions.rs:184:12 | LL | if (|| let 0 = 0) {} | ^^^ @@ -431,7 +431,7 @@ LL | if (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:188:9 + --> $DIR/disallowed-positions.rs:187:9 | LL | if (let 0 = 0)() {} | ^^^^^^^^^ @@ -439,7 +439,7 @@ LL | if (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -447,7 +447,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:12 + --> $DIR/disallowed-positions.rs:196:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -455,7 +455,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:198:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -463,7 +463,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:201:12 + --> $DIR/disallowed-positions.rs:200:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -471,7 +471,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:209:12 + --> $DIR/disallowed-positions.rs:208:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -479,13 +479,13 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: `||` operators are not supported in let chain conditions - --> $DIR/disallowed-positions.rs:212:16 + --> $DIR/disallowed-positions.rs:211:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:214:20 + --> $DIR/disallowed-positions.rs:213:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -493,7 +493,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:216:28 + --> $DIR/disallowed-positions.rs:215:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -501,7 +501,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:28 + --> $DIR/disallowed-positions.rs:217:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -509,7 +509,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:15 + --> $DIR/disallowed-positions.rs:221:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -517,7 +517,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:225:18 + --> $DIR/disallowed-positions.rs:224:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -525,7 +525,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:228:14 + --> $DIR/disallowed-positions.rs:227:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -533,7 +533,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:230:12 + --> $DIR/disallowed-positions.rs:229:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -541,7 +541,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:234:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -549,7 +549,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:237:11 + --> $DIR/disallowed-positions.rs:236:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -557,7 +557,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:243:11 + --> $DIR/disallowed-positions.rs:242:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -565,7 +565,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:249:11 + --> $DIR/disallowed-positions.rs:248:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -573,7 +573,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:253:22 + --> $DIR/disallowed-positions.rs:252:22 | LL | while let true = let true = true {} | ^^^ @@ -581,7 +581,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:18 + --> $DIR/disallowed-positions.rs:255:18 | LL | while return let 0 = 0 {} | ^^^ @@ -589,7 +589,7 @@ LL | while return let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:39 + --> $DIR/disallowed-positions.rs:258:39 | LL | 'outer: loop { while break 'outer let 0 = 0 {} } | ^^^ @@ -597,7 +597,7 @@ LL | 'outer: loop { while break 'outer let 0 = 0 {} } = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:262:18 + --> $DIR/disallowed-positions.rs:261:18 | LL | while (match let 0 = 0 { _ => { false } }) {} | ^^^ @@ -605,7 +605,7 @@ LL | while (match let 0 = 0 { _ => { false } }) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:265:12 + --> $DIR/disallowed-positions.rs:264:12 | LL | while (let 0 = 0, false).1 {} | ^^^^^^^^^ @@ -613,7 +613,7 @@ LL | while (let 0 = 0, false).1 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:268:12 + --> $DIR/disallowed-positions.rs:267:12 | LL | while (let 0 = 0,) {} | ^^^^^^^^^ @@ -621,7 +621,7 @@ LL | while (let 0 = 0,) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:16 + --> $DIR/disallowed-positions.rs:271:16 | LL | while (let 0 = 0).await {} | ^^^^^^^^^ @@ -629,7 +629,7 @@ LL | while (let 0 = 0).await {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:276:15 + --> $DIR/disallowed-positions.rs:275:15 | LL | while (|| let 0 = 0) {} | ^^^ @@ -637,7 +637,7 @@ LL | while (|| let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:279:12 + --> $DIR/disallowed-positions.rs:278:12 | LL | while (let 0 = 0)() {} | ^^^^^^^^^ @@ -645,7 +645,7 @@ LL | while (let 0 = 0)() {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:296:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | &let 0 = 0; | ^^^ @@ -653,7 +653,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:299:6 + --> $DIR/disallowed-positions.rs:298:6 | LL | !let 0 = 0; | ^^^ @@ -661,7 +661,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:301:6 + --> $DIR/disallowed-positions.rs:300:6 | LL | *let 0 = 0; | ^^^ @@ -669,7 +669,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:303:6 + --> $DIR/disallowed-positions.rs:302:6 | LL | -let 0 = 0; | ^^^ @@ -677,7 +677,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:305:13 + --> $DIR/disallowed-positions.rs:304:13 | LL | let _ = let _ = 3; | ^^^ @@ -685,7 +685,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:313:6 + --> $DIR/disallowed-positions.rs:312:6 | LL | (let 0 = 0)?; | ^^^ @@ -693,7 +693,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:316:13 + --> $DIR/disallowed-positions.rs:315:13 | LL | true || let 0 = 0; | ^^^ @@ -701,7 +701,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:318:14 + --> $DIR/disallowed-positions.rs:317:14 | LL | (true || let 0 = 0); | ^^^ @@ -709,7 +709,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:320:22 + --> $DIR/disallowed-positions.rs:319:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -717,7 +717,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:324:9 + --> $DIR/disallowed-positions.rs:323:9 | LL | x = let 0 = 0; | ^^^ @@ -725,7 +725,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:12 + --> $DIR/disallowed-positions.rs:326:12 | LL | true..(let 0 = 0); | ^^^ @@ -733,7 +733,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:329:8 + --> $DIR/disallowed-positions.rs:328:8 | LL | ..(let 0 = 0); | ^^^ @@ -741,7 +741,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:331:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let 0 = 0)..; | ^^^ @@ -749,7 +749,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:334:6 + --> $DIR/disallowed-positions.rs:333:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -757,7 +757,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:6 + --> $DIR/disallowed-positions.rs:337:6 | LL | (let true = let true = true); | ^^^ @@ -765,7 +765,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:338:17 + --> $DIR/disallowed-positions.rs:337:17 | LL | (let true = let true = true); | ^^^ @@ -773,7 +773,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:25 + --> $DIR/disallowed-positions.rs:343:25 | LL | let x = true && let y = 1; | ^^^ @@ -781,7 +781,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:350:19 + --> $DIR/disallowed-positions.rs:349:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -789,7 +789,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:6 + --> $DIR/disallowed-positions.rs:354:6 | LL | &let 0 = 0 | ^^^ @@ -797,7 +797,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:366:17 + --> $DIR/disallowed-positions.rs:365:17 | LL | true && let 1 = 1 | ^^^ @@ -805,7 +805,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:371:17 + --> $DIR/disallowed-positions.rs:370:17 | LL | true && let 1 = 1 | ^^^ @@ -813,7 +813,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:376:17 + --> $DIR/disallowed-positions.rs:375:17 | LL | true && let 1 = 1 | ^^^ @@ -821,7 +821,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:387:17 + --> $DIR/disallowed-positions.rs:386:17 | LL | true && let 1 = 1 | ^^^ @@ -829,7 +829,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:387:9 + --> $DIR/disallowed-positions.rs:386:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -840,124 +840,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:397:9 + --> $DIR/disallowed-positions.rs:396:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:401:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:9 + --> $DIR/disallowed-positions.rs:403:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:404:32 + --> $DIR/disallowed-positions.rs:403:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:9 + --> $DIR/disallowed-positions.rs:411:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:412:31 + --> $DIR/disallowed-positions.rs:411:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:9 + --> $DIR/disallowed-positions.rs:415:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:416:31 + --> $DIR/disallowed-positions.rs:415:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:420:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:440:22 + --> $DIR/disallowed-positions.rs:439:22 | LL | let x = (true && let y = 1); | ^^^ @@ -965,7 +965,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:445:20 + --> $DIR/disallowed-positions.rs:444:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 65beccf2214..142ea6b4ea8 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -1,5 +1,7 @@ -//@ revisions: no_feature feature nothing -//@ edition: 2021 +//@ revisions: e2021 e2024 nothing +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 +//@ [nothing] edition: 2024 // Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions. // // We want to make sure that `let` is banned in situations other than: @@ -19,9 +21,6 @@ // // To that end, we check some positions which is not part of the language above. -// Avoid inflating `.stderr` with overzealous gates (or test what happens if you disable the gate) -#![cfg_attr(not(no_feature), feature(let_chains))] - #![allow(irrefutable_let_patterns)] use std::ops::Range; @@ -50,8 +49,8 @@ fn _if() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement - //[no_feature]~| ERROR `let` expressions in this position are unstable - //[no_feature]~| ERROR `let` expressions in this position are unstable + //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later + //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later } #[cfg(not(nothing))] @@ -76,8 +75,8 @@ fn _while() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement - //[no_feature]~| ERROR `let` expressions in this position are unstable - //[no_feature]~| ERROR `let` expressions in this position are unstable + //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later + //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later } #[cfg(not(nothing))] @@ -89,13 +88,13 @@ fn _macros() { } } use_expr!((let 0 = 1 && 0 == 0)); - //[feature,no_feature]~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR expected expression, found `let` statement + //[e2021,e2024]~^ ERROR expected expression, found `let` statement + //[e2021,e2024]~| ERROR expected expression, found `let` statement + //[e2021,e2024]~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); - //[feature,no_feature]~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR expected expression, found `let` statement + //[e2021,e2024]~^ ERROR expected expression, found `let` statement + //[e2021,e2024]~| ERROR expected expression, found `let` statement + //[e2021,e2024]~| ERROR expected expression, found `let` statement } #[cfg(not(nothing))] @@ -112,7 +111,7 @@ fn nested_within_if_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { if let 0 = 0? {} - //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } if (let 0 = 0)? {} @@ -133,7 +132,7 @@ fn nested_within_if_expr() { if true..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types if ..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement if (let 0 = 0).. {} @@ -142,22 +141,22 @@ fn nested_within_if_expr() { // Binds as `(let ... = true)..true &&/|| false`. if let Range { start: _, end: _ } = true..true && false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types if let Range { start: _, end: _ } = true..true || false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types // Binds as `(let Range { start: F, end } = F)..(|| true)`. const F: fn() -> bool = || true; if let Range { start: F, end } = F..|| true {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types // Binds as `(let Range { start: true, end } = t)..(&&false)`. let t = &&true; if let Range { start: true, end } = t..&&false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types if let true = let true = true {} //~^ ERROR expected expression, found `let` statement @@ -203,7 +202,7 @@ fn nested_within_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { while let 0 = 0? {} - //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } while (let 0 = 0)? {} @@ -224,7 +223,7 @@ fn nested_within_while_expr() { while true..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types while ..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement while (let 0 = 0).. {} @@ -233,22 +232,22 @@ fn nested_within_while_expr() { // Binds as `(let ... = true)..true &&/|| false`. while let Range { start: _, end: _ } = true..true && false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types while let Range { start: _, end: _ } = true..true || false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types // Binds as `(let Range { start: F, end } = F)..(|| true)`. const F: fn() -> bool = || true; while let Range { start: F, end } = F..|| true {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types // Binds as `(let Range { start: true, end } = t)..(&&false)`. let t = &&true; while let Range { start: true, end } = t..&&false {} //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types while let true = let true = true {} //~^ ERROR expected expression, found `let` statement @@ -307,7 +306,7 @@ fn outside_if_and_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { let 0 = 0?; - //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } (let 0 = 0)?; @@ -333,7 +332,7 @@ fn outside_if_and_while_expr() { (let Range { start: _, end: _ } = true..true || false); //~^ ERROR expected expression, found `let` statement - //[feature,no_feature]~| ERROR mismatched types + //[e2021,e2024]~| ERROR mismatched types (let true = let true = true); //~^ ERROR expected expression, found `let` statement @@ -406,7 +405,7 @@ fn with_parenthesis() { //~| ERROR expected expression, found `let` statement } if let Some(a) = opt && (true && true) { - //[no_feature]~^ ERROR `let` expressions in this position are unstable + //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later } if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { @@ -422,18 +421,18 @@ fn with_parenthesis() { } if (true && (true)) && let Some(a) = opt { - //[no_feature]~^ ERROR `let` expressions in this position are unstable + //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later } if (true) && let Some(a) = opt { - //[no_feature]~^ ERROR `let` expressions in this position are unstable + //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later } if true && let Some(a) = opt { - //[no_feature]~^ ERROR `let` expressions in this position are unstable + //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later } let fun = || true; if let true = (true && fun()) && (true) { - //[no_feature]~^ ERROR `let` expressions in this position are unstable + //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later } #[cfg(false)] diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr index 23700f89f10..7fc91e9d980 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr @@ -1,65 +1,42 @@ -error[E0658]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:19:30 | LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:19:52 | LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:22:5 | LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:22:5 | LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:26:30 | LL | macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:26:52 | LL | macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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 6 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr index 3af844f4f96..35ac848561c 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr @@ -1,45 +1,30 @@ -error[E0658]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:19:30 | LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:19:52 | LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:22:5 | LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: `let` expressions in this position are unstable +error: let chains are only allowed in Rust 2024 or later --> $DIR/edition-gate-macro-error.rs:22:5 | LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs index 89b555d2c50..a56c11264c1 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs @@ -17,14 +17,14 @@ fn main() { // No gating if both the `if` and the chain are from a 2024 macro macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); - //~^ ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable + //~^ ERROR let chains are only allowed in Rust 2024 or later + //~| ERROR let chains are only allowed in Rust 2024 or later macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); - //~^ ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable + //~^ ERROR let chains are only allowed in Rust 2024 or later + //~| ERROR let chains are only allowed in Rust 2024 or later macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() }); - //[edition2021]~^ ERROR `let` expressions in this position are unstable - //[edition2021]~| ERROR `let` expressions in this position are unstable + //[edition2021]~^ ERROR let chains are only allowed in Rust 2024 or later + //[edition2021]~| ERROR let chains are only allowed in Rust 2024 or later macro_in_2024::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() }); } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.rs index dad02b7f106..0096e6985d3 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.rs @@ -1,6 +1,4 @@ -// gate-test-let_chains - -// Here we test feature gating for ´let_chains`. +// Here we test Rust 2024 edition gating for ´let_chains`. // See `disallowed-positions.rs` for the grammar // defining the language for gated allowed positions. @@ -12,17 +10,17 @@ fn _if() { if let 0 = 1 {} // Stable! if true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later if let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later if let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later if let 1 = 1 && let true = { true } && false { - //~^ ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later + //~| ERROR let chains are only allowed in Rust 2024 or later } } @@ -30,13 +28,13 @@ fn _while() { while let 0 = 1 {} // Stable! while true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later while let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later while let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are unstable [E0658] + //~^ ERROR let chains are only allowed in Rust 2024 or later } fn _macros() { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr new file mode 100644 index 00000000000..f75dd858941 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr @@ -0,0 +1,81 @@ +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:12:16 + | +LL | if true && let 0 = 1 {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:15:8 + | +LL | if let 0 = 1 && true {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:18:8 + | +LL | if let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:21:8 + | +LL | if let 1 = 1 && let true = { true } && false { + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:21:21 + | +LL | if let 1 = 1 && let true = { true } && false { + | ^^^^^^^^^^^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:30:19 + | +LL | while true && let 0 = 1 {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:33:11 + | +LL | while let 0 = 1 && true {} + | ^^^^^^^^^ + +error: let chains are only allowed in Rust 2024 or later + --> $DIR/edition-gate.rs:36:11 + | +LL | while let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/edition-gate.rs:52:20 + | +LL | #[cfg(false)] (let 0 = 1); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/edition-gate.rs:43:17 + | +LL | noop_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: no rules expected keyword `let` + --> $DIR/edition-gate.rs:54:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/edition-gate.rs:47:10 + | +LL | ($e:expr) => { + | ^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr deleted file mode 100644 index b9dac472dca..00000000000 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ /dev/null @@ -1,114 +0,0 @@ -error: expected expression, found `let` statement - --> $DIR/feature-gate.rs:54:20 - | -LL | #[cfg(false)] (let 0 = 1); - | ^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions - -error: expected expression, found `let` statement - --> $DIR/feature-gate.rs:45:17 - | -LL | noop_expr!((let 0 = 1)); - | ^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions - -error: no rules expected keyword `let` - --> $DIR/feature-gate.rs:56:15 - | -LL | macro_rules! use_expr { - | --------------------- when calling this macro -... -LL | use_expr!(let 0 = 1); - | ^^^ no rules expected this token in macro call - | -note: while trying to match meta-variable `$e:expr` - --> $DIR/feature-gate.rs:49:10 - | -LL | ($e:expr) => { - | ^^^^^^^ - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:14:16 - | -LL | if true && let 0 = 1 {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:17:8 - | -LL | if let 0 = 1 && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:20:8 - | -LL | if let Range { start: _, end: _ } = (true..true) && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:23:8 - | -LL | if let 1 = 1 && let true = { true } && false { - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:23:21 - | -LL | if let 1 = 1 && let true = { true } && false { - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:19 - | -LL | while true && let 0 = 1 {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:35:11 - | -LL | while let 0 = 1 && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:38:11 - | -LL | while let Range { start: _, end: _ } = (true..true) && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` 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 11 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs index ae525aed414..3711dd5abb2 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +//@ edition: 2024 fn main() { let _opt = Some(1i32); diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr index 130d0296c5e..008e769cf0b 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr @@ -1,19 +1,19 @@ error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:13:8 + --> $DIR/irrefutable-lets.rs:14:8 | -LL | if let first = &opt && let Some(ref second) = first && let None = second.start {} +LL | if let first = &opt && let Some(second) = first && let None = second.start {} | ^^^^^^^^^^^^^^^^ | = note: this pattern will always match = help: consider moving it outside of the construct note: the lint level is defined here - --> $DIR/irrefutable-lets.rs:6:30 + --> $DIR/irrefutable-lets.rs:7:30 | LL | #![cfg_attr(disallowed, deny(irrefutable_let_patterns))] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: irrefutable `if let` patterns - --> $DIR/irrefutable-lets.rs:19:8 + --> $DIR/irrefutable-lets.rs:20:8 | LL | if let first = &opt && let (a, b) = (1, 2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,25 +22,25 @@ LL | if let first = &opt && let (a, b) = (1, 2) {} = help: consider replacing the `if let` with a `let` error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:22:8 + --> $DIR/irrefutable-lets.rs:23:8 | -LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} +LL | if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {} | ^^^^^^^^^^^^^^^^ | = note: this pattern will always match = help: consider moving it outside of the construct error: trailing irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:22:87 + --> $DIR/irrefutable-lets.rs:23:83 | -LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} - | ^^^^^^^^^ +LL | if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {} + | ^^^^^^^^^ | = note: this pattern will always match = help: consider moving it into the body error: trailing irrefutable patterns in let chain - --> $DIR/irrefutable-lets.rs:26:37 + --> $DIR/irrefutable-lets.rs:27:37 | LL | if let Some(ref first) = opt && let second = first && let _third = second {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | if let Some(ref first) = opt && let second = first && let _third = seco = help: consider moving them into the body error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:29:8 + --> $DIR/irrefutable-lets.rs:30:8 | LL | if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | if let Range { start: local_start, end: _ } = (None..Some(1)) && let No = help: consider moving it outside of the construct error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:32:8 + --> $DIR/irrefutable-lets.rs:33:8 | LL | if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {} = help: consider moving it outside of the construct error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:35:8 + --> $DIR/irrefutable-lets.rs:36:8 | LL | if let first = &opt && let None = Some(1) {} | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | if let first = &opt && let None = Some(1) {} = help: consider moving it outside of the construct error: irrefutable `if let` guard patterns - --> $DIR/irrefutable-lets.rs:44:28 + --> $DIR/irrefutable-lets.rs:45:28 | LL | Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | Some(ref first) if let second = first && let _third = second && let = help: consider removing the guard and adding a `let` inside the match arm error: trailing irrefutable patterns in let chain - --> $DIR/irrefutable-lets.rs:59:16 + --> $DIR/irrefutable-lets.rs:60:16 | LL | && let v = local_end && let w = v => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | && let v = local_end && let w = v => {}, = help: consider moving them into the body error: irrefutable `while let` patterns - --> $DIR/irrefutable-lets.rs:68:11 + --> $DIR/irrefutable-lets.rs:69:11 | LL | while let first = &opt && let (a, b) = (1, 2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | while let first = &opt && let (a, b) = (1, 2) {} = help: consider instead using a `loop { ... }` with a `let` inside it error: trailing irrefutable patterns in let chain - --> $DIR/irrefutable-lets.rs:71:40 + --> $DIR/irrefutable-lets.rs:72:40 | LL | while let Some(ref first) = opt && let second = first && let _third = second {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | while let Some(ref first) = opt && let second = first && let _third = s = help: consider moving them into the body error: trailing irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:87:12 + --> $DIR/irrefutable-lets.rs:88:12 | LL | && let x = &opt | ^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | && let x = &opt = help: consider moving it into the body error: leading irrefutable pattern in let chain - --> $DIR/irrefutable-lets.rs:93:12 + --> $DIR/irrefutable-lets.rs:94:12 | LL | if let x = opt.clone().map(|_| 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs index e7d69f89773..c8b9ac313ba 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -1,7 +1,8 @@ //@ revisions: allowed disallowed //@[allowed] check-pass +//@ edition: 2024 -#![feature(if_let_guard, let_chains)] +#![feature(if_let_guard)] #![cfg_attr(allowed, allow(irrefutable_let_patterns))] #![cfg_attr(disallowed, deny(irrefutable_let_patterns))] @@ -10,16 +11,16 @@ use std::ops::Range; fn main() { let opt = Some(None..Some(1)); - if let first = &opt && let Some(ref second) = first && let None = second.start {} + if let first = &opt && let Some(second) = first && let None = second.start {} //[disallowed]~^ ERROR leading irrefutable pattern in let chain // No lint as the irrefutable pattern is surrounded by other stuff - if 4 * 2 == 0 && let first = &opt && let Some(ref second) = first && let None = second.start {} + if 4 * 2 == 0 && let first = &opt && let Some(second) = first && let None = second.start {} if let first = &opt && let (a, b) = (1, 2) {} //[disallowed]~^ ERROR irrefutable `if let` patterns - if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} + if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {} //[disallowed]~^ ERROR leading irrefutable pattern in let chain //[disallowed]~^^ ERROR trailing irrefutable pattern in let chain @@ -63,7 +64,7 @@ fn main() { // No error, despite the prefix being irrefutable: moving out could change the behaviour, // due to possible side effects of the operation. - while let first = &opt && let Some(ref second) = first && let None = second.start {} + while let first = &opt && let Some(second) = first && let None = second.start {} while let first = &opt && let (a, b) = (1, 2) {} //[disallowed]~^ ERROR irrefutable `while let` patterns diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs index 6d307be90c1..287c73b41e9 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs @@ -1,6 +1,7 @@ //@ run-pass +//@ edition: 2024 -#![feature(if_let_guard, let_chains)] +#![feature(if_let_guard)] fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool { if let Some(first) = opt diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs index 9f9002da674..424e70560db 100644 --- a/tests/ui/sanitizer/cfi/closures.rs +++ b/tests/ui/sanitizer/cfi/closures.rs @@ -31,7 +31,7 @@ fn dyn_fn_with_params() { #[test] fn call_fn_trait() { - let f: &(dyn Fn()) = &(|| {}) as _; + let f: &dyn Fn() = &(|| {}) as _; f.call(()); } @@ -47,7 +47,7 @@ fn use_fnmut<F: FnMut()>(mut f: F) { #[test] fn fn_to_fnmut() { - let f: &(dyn Fn()) = &(|| {}) as _; + let f: &dyn Fn() = &(|| {}) as _; use_fnmut(f); } diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 828b93da6be..5c4c50cb156 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -89,158 +89,182 @@ body: } } region_scope: Node(10) - match_span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0) - arms: [ - Arm { - pattern: - Pat: { - ty: bool - span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) - kind: PatKind { - Constant { - value: Ty(bool, true) - } - } - } - guard: None - body: + match_data: + LoopMatchMatchData { + span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0) + scrutinee: Expr { ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0) kind: Scope { - region_scope: Node(17) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17)) + region_scope: Node(12) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12)) value: Expr { ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0) kind: - NeverToAny { - source: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) - kind: - Block { - targeted_by_break: false + VarRef { + id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + } + } + } + } + arms: [ + Arm { + pattern: + Pat: { + ty: bool + span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) + kind: PatKind { + Constant { + value: Ty(bool, true) + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + kind: + Scope { + region_scope: Node(17) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + kind: + NeverToAny { + source: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) - region_scope: Node(18) - safety_mode: Safe - stmts: [ - Stmt { - kind: Expr { - scope: Node(21) - expr: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) - kind: - Scope { - region_scope: Node(19) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19)) - value: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) - kind: - ConstContinue ( - label: Node(10) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) - kind: - Scope { - region_scope: Node(20) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) - kind: - Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false) + kind: + Block { + targeted_by_break: false + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + region_scope: Node(18) + safety_mode: Safe + stmts: [ + Stmt { + kind: Expr { + scope: Node(21) + expr: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) + kind: + Scope { + region_scope: Node(19) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19)) + value: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) + kind: + ConstContinue ( + label: Node(10) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) + kind: + Scope { + region_scope: Node(20) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) + kind: + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false) + } } } - } - ) + ) + } } } } - } + } + ] + expr: [] } - ] - expr: [] } } } } } + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16)) + scope: Node(16) + span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0) } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16)) - scope: Node(16) - span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0) - } - Arm { - pattern: - Pat: { - ty: bool - span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) - kind: PatKind { - Constant { - value: Ty(bool, false) + Arm { + pattern: + Pat: { + ty: bool + span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) + kind: PatKind { + Constant { + value: Ty(bool, false) + } + } } - } - } - guard: None - body: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - Scope { - region_scope: Node(25) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - NeverToAny { - source: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - Return { - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) - kind: - Scope { - region_scope: Node(26) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) - kind: - VarRef { - id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + guard: None + body: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + Scope { + region_scope: Node(25) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + NeverToAny { + source: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + Return { + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) + kind: + Scope { + region_scope: Node(26) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + } } } } @@ -250,12 +274,12 @@ body: } } } + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24)) + scope: Node(24) + span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0) } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24)) - scope: Node(24) - span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0) + ] } - ] } } } diff --git a/tests/ui/traits/const-traits/const-via-item-bound.rs b/tests/ui/traits/const-traits/const-via-item-bound.rs new file mode 100644 index 00000000000..23f122b7413 --- /dev/null +++ b/tests/ui/traits/const-traits/const-via-item-bound.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(const_trait_impl)] + +#[const_trait] +trait Bar {} + +trait Baz: const Bar {} + +trait Foo { + // Well-formedenss of `Baz` requires `<Self as Foo>::Bar: const Bar`. + // Make sure we assemble a candidate for that via the item bounds. + type Bar: Baz; +} + +fn main() {} diff --git a/tests/ui/traits/dyn-trait.rs b/tests/ui/traits/dyn-trait.rs index 4fb7aea5cba..a378ce5a696 100644 --- a/tests/ui/traits/dyn-trait.rs +++ b/tests/ui/traits/dyn-trait.rs @@ -7,7 +7,7 @@ static BYTE: u8 = 33; fn main() { let x: &(dyn 'static + Display) = &BYTE; let y: Box<dyn Display + 'static> = Box::new(BYTE); - let _: &dyn (Display) = &BYTE; + let _: &dyn Display = &BYTE; let _: &dyn (::std::fmt::Display) = &BYTE; let xstr = format!("{}", x); let ystr = format!("{}", y); diff --git a/tests/ui/traits/impl-2.rs b/tests/ui/traits/impl-2.rs index 41fa1cd334f..eafbaeaa167 100644 --- a/tests/ui/traits/impl-2.rs +++ b/tests/ui/traits/impl-2.rs @@ -10,7 +10,7 @@ pub mod Foo { } mod Bar { - impl<'a> dyn (crate::Foo::Trait) + 'a { + impl<'a> dyn crate::Foo::Trait + 'a { fn bar(&self) { self.foo() } } } diff --git a/tests/ui/underscore-lifetime/in-binder.stderr b/tests/ui/underscore-lifetime/in-binder.stderr index fcd7eddb576..f25db4d0889 100644 --- a/tests/ui/underscore-lifetime/in-binder.stderr +++ b/tests/ui/underscore-lifetime/in-binder.stderr @@ -3,36 +3,48 @@ error[E0637]: `'_` cannot be used here | LL | impl<'_> IceCube<'_> {} | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:12:15 | LL | struct Struct<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:17:11 | LL | enum Enum<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:22:13 | LL | union Union<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:27:13 | LL | trait Trait<'_> { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/in-binder.rs:31:8 | LL | fn foo<'_>() { | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error: aborting due to 6 previous errors diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr index d940166e9e2..50359309c92 100644 --- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -15,12 +15,16 @@ error[E0637]: `'_` cannot be used here | LL | fn foo<'_> | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0637]: `'_` cannot be used here --> $DIR/underscore-lifetime-binders.rs:10:25 | LL | fn meh() -> Box<dyn for<'_> Meh<'_>> | ^^ `'_` is a reserved lifetime name + | + = help: use another lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 |
