diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index c5d8d758c4733..11aa18cdb224d 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -126,6 +126,13 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display { } impl<'a, Ty> TyAndLayout<'a, Ty> { + /// Synthetize a layout representing the variant-specific fields of an enum-like layout. + /// + /// Note that the resulting layout *does not* fully describes `self.ty` at that specific + /// variant: prefix fields (e.g. in coroutines) and tag information are lost. + /// + /// If you don't need type information about the variant's fields, prefer using + /// `self.layout.variants` directly. pub fn for_variant(self, cx: &C, variant_index: VariantIdx) -> Self where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index e0e9ecaa49c63..1e0fd78b4dd75 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2203,6 +2203,17 @@ impl LayoutData { pub fn is_uninhabited(&self) -> bool { self.uninhabited } + + /// Returns `true` if the given variant is uninhabited. + pub fn is_variant_uninhabited(&self, variant: VariantIdx) -> bool { + match self.variants { + Variants::Empty => true, + Variants::Single { index } => variant != index || self.uninhabited, + Variants::Multiple { ref variants, .. } => { + variants.get(variant).map(|v| v.uninhabited).unwrap_or(true) + } + } + } } impl fmt::Debug for LayoutData diff --git a/compiler/rustc_ast_ir/src/visit.rs b/compiler/rustc_ast_ir/src/visit.rs index 8315c080dfa86..1a60688312473 100644 --- a/compiler/rustc_ast_ir/src/visit.rs +++ b/compiler/rustc_ast_ir/src/visit.rs @@ -99,7 +99,7 @@ macro_rules! walk_list { macro_rules! walk_visitable_list { ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => { for elem in $list { - $crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?)); + $crate::try_visit!(::rustc_type_ir::TypeVisitable::visit_with(elem, $visitor $(, $($extra_args,)* )?)); } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/unroll.rs b/compiler/rustc_attr_parsing/src/attributes/unroll.rs index 3438fc044ec55..5a49feca2a1ea 100644 --- a/compiler/rustc_attr_parsing/src/attributes/unroll.rs +++ b/compiler/rustc_attr_parsing/src/attributes/unroll.rs @@ -6,7 +6,8 @@ use super::prelude::*; pub(crate) struct UnrollParser; impl SingleAttributeParser for UnrollParser { - const PATH: &[Symbol] = &[sym::unroll]; + // FIXME(#159429): temporarily renamed to mitigate `#[unroll]` nameres ambiguity. + const PATH: &[Symbol] = &[sym::rustc_unroll]; const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Loop), Allow(Target::ForLoop), diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 5bf692eaa7205..5bfe5ee64f050 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -2,9 +2,7 @@ use std::fmt; use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; -use rustc_middle::mir::{ - self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, -}; +use rustc_middle::mir::{self, BasicBlock, Body, CallReturnPlaces, Location, Place}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{ @@ -76,19 +74,15 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - term: &'mir mir::Terminator<'tcx>, + term: &mir::Terminator<'tcx>, loc: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc); self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc); self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc); - - // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this - // analysis doesn't use. - TerminatorEdges::None } fn apply_call_return_effect( @@ -598,12 +592,12 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { self.kill_loans_out_of_scope_at_location(state, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind { for op in operands { if let mir::InlineAsmOperand::Out { place: Some(place), .. } @@ -613,7 +607,6 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } } } - terminator.edges() } } diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index 8818e8634952e..fd4f1d8c61e55 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -14,7 +14,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( variant_index: VariantIdx, ) { let layout = place.layout(); - if layout.for_variant(fx, variant_index).is_uninhabited() { + if layout.is_variant_uninhabited(variant_index) { return; } match layout.variants { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index b592e4a339346..14a5f71fbceaa 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -477,7 +477,7 @@ pub(super) fn codegen_tag_value<'tcx, V>( ) -> Result, UninhabitedVariantError> { // By checking uninhabited-ness first we don't need to worry about types // like `(u32, !)` which are single-variant but weird. - if layout.for_variant(cx, variant_index).is_uninhabited() { + if layout.is_variant_uninhabited(variant_index) { return Err(UninhabitedVariantError); } diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index a230f797b56fd..29b6e26d950d5 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; use rustc_index::bit_set::MixedBitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges, + self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, }; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::{Analysis, JoinSemiLattice}; @@ -351,14 +351,13 @@ where self.transfer_function(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.transfer_function(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index a1776c6ba3d13..9d0499102c08e 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -210,7 +210,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Reading the discriminant of an uninhabited variant is UB. This is the basis for the // `uninhabited_enum_branching` MIR pass. It also ensures consistency with // `write_discriminant`. - if op.layout().for_variant(self, index).is_uninhabited() { + if op.layout().is_variant_uninhabited(index) { throw_ub!(UninhabitedEnumVariantRead(Some(index))) } interp_ok(index) @@ -252,7 +252,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Therefore, there's no way to represent those variants in the given layout. // Essentially, uninhabited variants do not have a tag that corresponds to their // discriminant, so we have to bail out here. - if layout.for_variant(self, variant_index).is_uninhabited() { + if layout.is_variant_uninhabited(variant_index) { throw_ub!(UninhabitedEnumVariantWritten(variant_index)) } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 045233c0c4d21..4846b48af8d5e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -858,6 +858,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { + self.gate_proc_macro_attr_item(span, &item); // `LegacyAttr` is only used for builtin attribute macros, which have their // safety checked by `check_builtin_meta_item`, so we don't need to check // `unsafety` here. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 72b51ad204b9d..bc6f87a2a7f17 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -217,10 +217,12 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ // - https://github.com/rust-lang/rust/issues/153629 sym::rustc_splat, - // The `#[unroll]` attribute. + // The `#[rustc_unroll]` attribute. // // - https://github.com/rust-lang/rust/pull/156816 - sym::unroll, + // + // FIXME(#159429): temporarily renamed to mitigate `#[unroll]` nameres ambiguity + sym::rustc_unroll, // `#[instrument_fn = "on|off"]` to insert or inhibit instrumentation function // calls inside a function, usually around the prologue. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 530483e87329c..94241e6a31eb0 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1706,7 +1706,8 @@ pub enum AttributeKind { limit: Limit, }, - /// Represents `#[unroll]` + /// Represents `#[rustc_unroll]` + // FIXME(#159429): temporarily renamed from `#[unroll]` to mitigate nameres ambiguity Unroll(UnrollAttr), /// Represents `#[unstable_feature_bound]`. diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 97cc76d833e9e..a9d524711a141 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -2,6 +2,7 @@ use std::any::Any; use std::mem; use std::sync::Arc; +use rustc_data_structures::unord::ExtendUnord; use rustc_hir::attrs::Deprecation; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; @@ -472,7 +473,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // the former. // This is a rudimentary check that does not catch all cases, // just the easiest. - let mut fallback_map: Vec<(DefId, DefId)> = Default::default(); + let mut fallback_map: DefIdMap = Default::default(); // Issue 46112: We want the map to prefer the shortest // paths when reporting the path to an item. Therefore we @@ -533,14 +534,24 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } } Entry::Vacant(entry) => { + if !fallback { + entry.insert(parent); + } + + // Make sure that we have not already explored this child + // through a previous fallback entry further up the BFS, + // in which case we do not want to put it back into the BFS queue, + // nor record a new fallback parent. + if fallback_map.contains_key(&def_id) { + return; + } + if fallback { // We do all of the same steps to fallback entries as to // preferred entries, except for recording them in a separate map. // It is important to not return early in the fallback cases to // ensure that we extend the BFS to the children of fallback items. - fallback_map.push((def_id, parent)); - } else { - entry.insert(parent); + fallback_map.insert(def_id, parent); } if child.res.module_like_def_id().is_some() { @@ -560,12 +571,13 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // Fill in any missing entries with the less preferable path. // If this path re-exports the child as `_`, we still use this // path in a diagnostic that suggests importing `::*`. + // We must extend the fallback map with items from the visible parent map + // as the extend call overrides existing entries from the latter map, + // which we prefer over fallback entries. + let mut merged_visible_parent_map = fallback_map; + merged_visible_parent_map.extend_unord(visible_parent_map.into_items()); - for (child, parent) in fallback_map { - visible_parent_map.entry(child).or_insert(parent); - } - - visible_parent_map + merged_visible_parent_map }, dependency_formats: |tcx, ()| Arc::new(crate::dependency_format::calculate(tcx)), diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 9e7e4f2fe0c4f..470abf327679f 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -1,6 +1,5 @@ //! Implementation of [`rustc_type_ir::Interner`] for [`TyCtxt`]. -use std::ops::ControlFlow; use std::{debug_assert_matches, fmt}; use rustc_data_structures::Limit; @@ -14,7 +13,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::{ BoundVar, CollectAndApply, DebruijnIndex, Interner, TypeFoldable, Unnormalized, VisitorResult, - search_graph, + search_graph, try_visit, }; use crate::dep_graph::{DepKind, DepNodeIndex}; @@ -560,10 +559,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> R { let trait_impls = self.trait_impls_of(trait_def_id); for &impl_def_id in trait_impls.blanket_impls() { - match f(impl_def_id).branch() { - ControlFlow::Break(b) => return R::from_residual(b), - ControlFlow::Continue(()) => {} - } + try_visit!(f(impl_def_id)); } R::output() diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index da514036b20b9..5309e35b1073c 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,4 @@ use std::iter; -use std::ops::ControlFlow; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; @@ -13,7 +12,7 @@ use tracing::debug; use crate::query::LocalCrate; use crate::traits::specialization_graph; use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use crate::ty::{self, Ident, Interner, RestrictionKind, Ty, TyCtxt, VisitorResult}; +use crate::ty::{self, Ident, Interner, RestrictionKind, Ty, TyCtxt, VisitorResult, try_visit}; /// A trait's definition with type information. #[derive(StableHash, Encodable, Decodable)] @@ -142,21 +141,12 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, mut f: impl FnMut(DefId) -> R, ) -> R { - macro_rules! ret { - ($e: expr) => { - match $e.branch() { - ControlFlow::Break(b) => return R::from_residual(b), - ControlFlow::Continue(()) => {} - } - }; - } - let tcx = self; let trait_impls = tcx.trait_impls_of(trait_def_id); let mut consider_impls_for_simplified_type = |simp| { if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { for &impl_def_id in impls_for_type { - ret!(f(impl_def_id)) + try_visit!(f(impl_def_id)) } } @@ -191,7 +181,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::fast_reject::TreatParams::AsRigid, ) .unwrap(); - ret!(consider_impls_for_simplified_type(simp)); + try_visit!(consider_impls_for_simplified_type(simp)); } // HACK: For integer and float variables we have to manually look at all impls @@ -219,7 +209,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::SimplifiedType::Uint(Usize), ]; for simp in possible_integers { - ret!(consider_impls_for_simplified_type(simp)); + try_visit!(consider_impls_for_simplified_type(simp)); } } @@ -234,7 +224,7 @@ impl<'tcx> TyCtxt<'tcx> { ]; for simp in possible_floats { - ret!(consider_impls_for_simplified_type(simp)); + try_visit!(consider_impls_for_simplified_type(simp)); } } @@ -245,14 +235,14 @@ impl<'tcx> TyCtxt<'tcx> { self_ty, ty::fast_reject::TreatParams::AsRigid, ) { - ret!(consider_impls_for_simplified_type(simp)); + try_visit!(consider_impls_for_simplified_type(simp)); } } // This is only for diagnostics and normally ty vars should be handled by the callers. ty::Infer(ty::TyVar(_)) => { for &impl_def_id in trait_impls.non_blanket_impls().values().flatten() { - ret!(f(impl_def_id)); + try_visit!(f(impl_def_id)); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 68c8e03de8022..7b577c2b9df4c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -194,7 +194,9 @@ impl Direction for Forward { let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; analysis.apply_early_terminator_effect(state, terminator, location); - let edges = analysis.apply_primary_terminator_effect(state, terminator, location); + // Edges are obtained *before* calling `apply_primary_terminator_effect`. + let edges = analysis.get_terminator_edges(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); let exit_state = state; match edges { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 8f58846152747..b767ed6005346 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -196,19 +196,30 @@ pub trait Analysis<'tcx> { ) { } + /// Gets the terminator edges. Used by forward analyses only. Called *before* + /// `apply_primary_terminator_effect` is applied; this might seem strange but in practice + /// `MaybeInitializedPlaces` needs that ordering and other analyses work with either ordering. + fn get_terminator_edges<'mir>( + &self, + _state: &Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + terminator.edges() + } + /// Updates the current dataflow state with the effect of evaluating a terminator. /// /// The effect of a successful return from a `Call` terminator should **not** be accounted for /// in this function. That should go in `apply_call_return_effect`. For example, in the /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, _state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - terminator.edges() + ) { } /* Edge-specific effects */ diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 86ea3a34ae0ea..ee6330bfe1c2c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -197,15 +197,14 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { assert!(state.insert(idx)); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); - terminator.edges() } } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 9ec68f5260c05..c5b69c563b2fe 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -41,14 +41,13 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { Self::transfer_function(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { Self::transfer_function(state).visit_terminator(terminator, location); - terminator.edges() } } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 543c833326021..1b2c58c7e514c 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -391,14 +391,15 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + state: &Self::Domain, terminator: &'mir mir::Terminator<'tcx>, - location: Location, + _location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - // Note: `edges` must be computed first because `drop_flag_effects_for_location` can change - // the result of `is_unwind_dead`. + // Note: this relies on `get_terminator_edges` being called before + // `apply_primary_terminator_effect` because the result of `is_unwind_dead` is affected by + // the `drop_flag_effects_for_location` in `apply_primary_terminator_effect`. let mut edges = terminator.edges(); if self.skip_unreachable_unwind && let mir::TerminatorKind::Drop { target, unwind, place, replace: _, drop: _ } = @@ -408,10 +409,18 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { { edges = TerminatorEdges::Single(target); } + edges + } + + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { Self::update_bits(state, path, s) }); - edges } fn apply_call_return_effect( @@ -514,15 +523,12 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + _state: &Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { - Self::update_bits(state, path, s) - }); if self.skip_unreachable_unwind.contains(location.block) { let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; assert_matches!(unwind, mir::UnwindAction::Cleanup(_)); @@ -532,6 +538,17 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { + Self::update_bits(state, path, s) + }); + } + fn apply_call_return_effect( &self, state: &mut Self::Domain, @@ -633,13 +650,13 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } - #[instrument(skip(self, state, terminator), level = "debug")] - fn apply_primary_terminator_effect<'mir>( + #[instrument(skip(self, state, _terminator), level = "debug")] + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { let move_data = self.move_data(); let init_loc_map = &move_data.init_loc_map; @@ -652,7 +669,6 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { None } })); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index b690e86b747d5..da2ea948366db 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,8 +1,6 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{ - self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, -}; +use rustc_middle::mir::{self, CallReturnPlaces, Local, Location, Place, StatementKind}; use crate::{Analysis, Backward, GenKill}; @@ -55,14 +53,13 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { TransferFunction(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { TransferFunction(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( @@ -301,14 +298,13 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { TransferFunction(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { TransferFunction(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 494fb4098cfc1..558bf0a5603fa 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -295,12 +295,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage { } } - fn apply_primary_terminator_effect<'t>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'t Terminator<'tcx>, + terminator: &Terminator<'tcx>, loc: Location, - ) -> TerminatorEdges<'t, 'tcx> { + ) { match terminator.kind { // For call terminators the destination requires storage for the call // and after the call returns successfully, but not after a panic. @@ -333,7 +333,6 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage { } self.check_for_move(state, loc); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7f2e5c05eb5d3..4e00bf1bf6559 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -122,19 +122,34 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + state: &Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, ) -> TerminatorEdges<'mir, 'tcx> { if state.is_reachable() { - self.handle_terminator(terminator, state) + if let TerminatorKind::SwitchInt { discr, targets } = &terminator.kind { + self.get_switch_int_edges(discr, targets, state) + } else { + terminator.edges() + } } else { TerminatorEdges::None } } + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + terminator: &Terminator<'tcx>, + _location: Location, + ) { + if state.is_reachable() { + self.handle_terminator(terminator, state) + } + } + fn apply_call_return_effect( &self, state: &mut Self::Domain, @@ -204,16 +219,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } - fn handle_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State>, - ) -> ValueOrPlace> { + fn handle_operand(&self, operand: &Operand<'tcx>) -> ValueOrPlace> { match operand { Operand::RuntimeChecks(_) => ValueOrPlace::TOP, - Operand::Constant(constant) => { - ValueOrPlace::Value(self.handle_constant(constant, state)) - } + Operand::Constant(constant) => ValueOrPlace::Value(self.handle_constant(constant)), Operand::Copy(place) | Operand::Move(place) => { // On move, we would ideally flood the place with bottom. But with the current // framework this is not possible (similar to `InterpCx::eval_operand`). @@ -228,7 +237,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { &self, terminator: &'mir Terminator<'tcx>, state: &mut State>, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { match &terminator.kind { TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { // Effect is applied by `handle_call_return`. @@ -240,14 +249,12 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // They would have an effect, but are not allowed in this phase. bug!("encountered disallowed terminator"); } - TerminatorKind::SwitchInt { discr, targets } => { - return self.handle_switch_int(discr, targets, state); - } TerminatorKind::TailCall { .. } => { // FIXME(explicit_tail_calls): determine if we need to do something here (probably // not) } - TerminatorKind::Goto { .. } + TerminatorKind::SwitchInt { .. } + | TerminatorKind::Goto { .. } | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return @@ -259,7 +266,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // These terminators have no effect on the analysis. } } - terminator.edges() } fn handle_call_return( @@ -376,7 +382,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { operand, _, ) => { - let pointer = self.handle_operand(operand, state); + let pointer = self.handle_operand(operand); state.assign(target.as_ref(), pointer, &self.map); if let Some(target_len) = self.map.find_len(target.as_ref()) @@ -461,7 +467,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), - Rvalue::Use(operand, _) => return self.handle_operand(operand, state), + Rvalue::Use(operand, _) => return self.handle_operand(operand), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::Ref(..) | Rvalue::Reborrow(..) | Rvalue::RawPtr(..) => { // We don't track such places. @@ -480,24 +486,20 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { ValueOrPlace::Value(val) } - fn handle_constant( - &self, - constant: &ConstOperand<'tcx>, - _state: &mut State>, - ) -> FlatSet { + fn handle_constant(&self, constant: &ConstOperand<'tcx>) -> FlatSet { constant .const_ .try_eval_scalar(self.tcx, self.typing_env) .map_or(FlatSet::Top, FlatSet::Elem) } - fn handle_switch_int<'mir>( + fn get_switch_int_edges<'mir>( &self, discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, - state: &mut State>, + state: &State>, ) -> TerminatorEdges<'mir, 'tcx> { - let value = match self.handle_operand(discr, state) { + let value = match self.handle_operand(discr) { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; @@ -676,7 +678,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { op: &Operand<'tcx>, state: &mut State>, ) -> FlatSet> { - let value = match self.handle_operand(op, state) { + let value = match self.handle_operand(op) { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 32951ea0162a6..c895819a9f8cc 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1342,14 +1342,13 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { self.transfer_function(trans).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, trans: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.transfer_function(trans).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 5c66d2be7dfdd..31c7d9af33bee 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -20,6 +20,10 @@ pub(super) struct TokenTreeDiagInfo { /// Collect empty block spans that might have been auto-inserted by editors. pub empty_block_spans: Vec, + /// Spans of `&&`/`||` tokens that directly open a brace-delimited block, + /// which usually means the user meant to continue an if-let chain. + pub if_let_chain_hint_spans: Vec, + /// Collect the spans of braces (Open, Close). Used only /// for detecting if blocks are empty and only braces. pub matching_block_spans: Vec<(Span, Span)>, @@ -124,6 +128,10 @@ pub(super) fn report_suspicious_mismatch_block( err.span_label(parent.1, "...matches this closing brace"); } } + + for span in diag_info.if_let_chain_hint_spans.iter() { + err.span_label(*span, "you might have meant to continue an if-let chain here"); + } } pub(crate) fn make_errors_for_mismatched_closing_delims<'psess>( diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 757cd755bf65f..3455947471503 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -90,6 +90,15 @@ impl<'psess, 'src> Lexer<'psess, 'src> { self.diag_info.matching_block_spans.push((pre_span, close_delimiter_span)); } + // A brace-delimited block whose first token is `&&`/`||` usually means + // the user meant to continue an if-let chain, e.g. `if let P = e { && cond {`. + if Delimiter::Brace == open_delim + && let Some(TokenTree::Token(tok, _)) = tts.iter().next() + && matches!(tok.kind, token::AndAnd | token::OrOr) + { + self.diag_info.if_let_chain_hint_spans.push(tok.span); + } + // Move past the closing delimiter. self.bump_minimal() } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ff1d4253c4414..a346a5216128b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1872,6 +1872,8 @@ symbols! { rustc_test_marker, rustc_then_this_would_need, rustc_trivial_field_reads, + // FIXME(#159429): temporary rename to avoid `#[unroll]` nameres ambiguity + rustc_unroll, rustdoc, rustdoc_internals, rustdoc_missing_doc_code_examples, @@ -2254,7 +2256,6 @@ symbols! { unreachable_display, unreachable_macro, unrestricted_attribute_tokens, - unroll, unsafe_attributes, unsafe_binders, unsafe_block_in_unsafe_fn, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e5d3ccb027b70..a5896f3f863cf 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1611,7 +1611,7 @@ pub trait UpperExp: PointeeSized { /// /// let mut output = String::new(); /// fmt::write(&mut output, format_args!("Hello {}!", "world")) -/// .expect("Error occurred while trying to write in String"); +/// .expect("Writing to a `String` should not fail"); /// assert_eq!(output, "Hello world!"); /// ``` /// @@ -1622,7 +1622,7 @@ pub trait UpperExp: PointeeSized { /// /// let mut output = String::new(); /// write!(&mut output, "Hello {}!", "world") -/// .expect("Error occurred while trying to write in String"); +/// .expect("Writing to a `String` should not fail"); /// assert_eq!(output, "Hello world!"); /// ``` /// diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index de3029bc0e620..652e797538223 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2350,17 +2350,13 @@ impl CommandLineStep for Assemble { let is_dylib_or_debug = is_dylib(&f.path()) || is_debug_info(&filename); // If we link statically to stdlib, do not copy the libstd dynamic library file - // FIXME: Also do this for Windows once incremental post-optimization stage0 tests - // work without std.dll (see https://github.com/rust-lang/rust/pull/131188). - let can_be_rustc_dynamic_dep = if builder - .link_std_into_rustc_driver(target_compiler.host) - && !target_compiler.host.is_windows() - { - let is_std = filename.starts_with("std-") || filename.starts_with("libstd-"); - !is_std - } else { - true - }; + let can_be_rustc_dynamic_dep = + if builder.link_std_into_rustc_driver(target_compiler.host) { + let is_std = filename.starts_with("std-") || filename.starts_with("libstd-"); + !is_std + } else { + true + }; if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro { builder.copy_link(&f.path(), &rustc_libdir.join(&filename), FileType::Regular); diff --git a/src/ci/docker/scripts/stage_2_test_set1.sh b/src/ci/docker/scripts/stage_2_test_set1.sh index e7930513c0d62..62b3c2c051a40 100755 --- a/src/ci/docker/scripts/stage_2_test_set1.sh +++ b/src/ci/docker/scripts/stage_2_test_set1.sh @@ -4,6 +4,8 @@ set -ex # Run a subset of tests. Used to run tests in parallel in multiple jobs. +# NOTE: keep in sync with `aarch64-apple*-{1,2}` jobs. + # When this job partition is run as part of PR CI, skip tidy to allow revealing more failures. The # dedicated `tidy` job failing won't block other PR CI jobs from completing, and so tidy failures # shouldn't inhibit revealing other failures in PR CI jobs. diff --git a/src/ci/docker/scripts/stage_2_test_set2.sh b/src/ci/docker/scripts/stage_2_test_set2.sh index 5963924cce529..c0cdc31011378 100755 --- a/src/ci/docker/scripts/stage_2_test_set2.sh +++ b/src/ci/docker/scripts/stage_2_test_set2.sh @@ -4,6 +4,8 @@ set -ex # Run a subset of tests. Used to run tests in parallel in multiple jobs. +# NOTE: keep in sync with `aarch64-apple*-{1,2}` jobs. + # When this job partition is run as part of PR CI, skip tidy to allow revealing more failures. The # dedicated `tidy` job failing won't block other PR CI jobs from completing, and so tidy failures # shouldn't inhibit revealing other failures in PR CI jobs. diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 5e1ef98906d00..20e52b6b52297 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -586,11 +586,41 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos-15 - - name: aarch64-apple + - name: aarch64-apple-1 env: - SCRIPT: > - ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin && - ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin src/tools/cargo + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set1.sh` + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip compiler + --skip src + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set build.allocator=jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-15 + + - name: aarch64-apple-2 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, + # union `src/tools/cargo` specifically. + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip tests + --skip library + --skip tidyselftest + && ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + src/tools/cargo RUST_CONFIGURE_ARGS: >- --enable-sanitizers --enable-profiler @@ -607,12 +637,43 @@ auto: # previous attempts have timed out multiple times. Remove/revert this job if # this hangs or times out, or if it becomes the slowest Merge CI job, and let # T-infra know. - - name: aarch64-apple-macos-26 + - name: aarch64-apple-macos-26-1 doc_url: https://github.com/rust-lang/rust/issues/157687 env: - SCRIPT: > - ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin && - ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin src/tools/cargo + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set1.sh` + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip compiler + --skip src + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-26 + + - name: aarch64-apple-macos-26-2 + doc_url: https://github.com/rust-lang/rust/issues/157687 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, + # union `src/tools/cargo` specifically. + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip tests + --skip library + --skip tidyselftest + && ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + src/tools/cargo RUST_CONFIGURE_ARGS: >- --enable-sanitizers --enable-profiler diff --git a/src/doc/unstable-book/src/language-features/loop-hints.md b/src/doc/unstable-book/src/language-features/loop-hints.md index c02411d30c668..b82a7b367095a 100644 --- a/src/doc/unstable-book/src/language-features/loop-hints.md +++ b/src/doc/unstable-book/src/language-features/loop-hints.md @@ -6,18 +6,22 @@ The tracking issue for this feature is: [#156874] ------ + + Loop unrolling can be a powerful optimization but like inlining, it is sometimes useful to manually provide hints to optimizations. -`#[unroll]` will encourage unrolling of a loop. +`#[rustc_unroll]` will encourage unrolling of a loop. -`#[unroll(full)]` is a stronger hint and can cause optimizations to completely ignore the code +`#[rustc_unroll(full)]` is a stronger hint and can cause optimizations to completely ignore the code side growth from repeating a loop body. -`#[unroll(never)]` is a strong hint to not unroll the loop at all. Note that other loop +`#[rustc_unroll(never)]` is a strong hint to not unroll the loop at all. Note that other loop optimizations may still be applied. -`#[unroll(N)]` is a hint to unroll `N` iterations of the loop. +`#[rustc_unroll(N)]` is a hint to unroll `N` iterations of the loop. In all cases these are just hints and may be ignored. But unlike function inlining hints, loops tend to be heavily modified during compilation, which can make obeying hints challenging. diff --git a/tests/codegen-llvm/loop-attrs/unroll-for-metadata.rs b/tests/codegen-llvm/loop-attrs/unroll-for-metadata.rs index 64113fbeb3247..60f9b6da6c9fe 100644 --- a/tests/codegen-llvm/loop-attrs/unroll-for-metadata.rs +++ b/tests/codegen-llvm/loop-attrs/unroll-for-metadata.rs @@ -15,7 +15,7 @@ unsafe extern "C" { pub fn unroll_hint() { // CHECK-LABEL: @unroll_hint // CHECK: !llvm.loop ![[HINT:[0-9]+]] - #[unroll] + #[rustc_unroll] for _ in 0..10 { unsafe { maybe_has_side_effect() } } @@ -25,7 +25,7 @@ pub fn unroll_hint() { pub fn unroll_full() { // CHECK-LABEL: @unroll_full // CHECK: !llvm.loop ![[FULL:[0-9]+]] - #[unroll(full)] + #[rustc_unroll(full)] for _ in 0..10 { unsafe { maybe_has_side_effect() } } @@ -35,7 +35,7 @@ pub fn unroll_full() { pub fn unroll_never() { // CHECK-LABEL: @unroll_never // CHECK: !llvm.loop ![[DISABLE:[0-9]+]] - #[unroll(never)] + #[rustc_unroll(never)] for _ in 0..10 { unsafe { maybe_has_side_effect() } } @@ -45,7 +45,7 @@ pub fn unroll_never() { pub fn unroll_count() { // CHECK-LABEL: @unroll_count // CHECK: !llvm.loop ![[COUNT:[0-9]+]] - #[unroll(5)] + #[rustc_unroll(5)] for _ in 0..10 { unsafe { maybe_has_side_effect() } } diff --git a/tests/codegen-llvm/loop-attrs/unroll-for-works.rs b/tests/codegen-llvm/loop-attrs/unroll-for-works.rs index b2f8b58c93573..0aa8d805c4f68 100644 --- a/tests/codegen-llvm/loop-attrs/unroll-for-works.rs +++ b/tests/codegen-llvm/loop-attrs/unroll-for-works.rs @@ -11,7 +11,7 @@ unsafe extern "C" { pub fn unroll_full() { // CHECK-LABEL: @unroll_full // CHECK-COUNT-512: tail call void @maybe_has_side_effect() - #[unroll(full)] + #[rustc_unroll(full)] for _ in 0..512 { unsafe { maybe_has_side_effect() } } @@ -22,7 +22,7 @@ pub fn unroll_never() { // CHECK-LABEL: @unroll_never // CHECK: tail call void @maybe_has_side_effect() // CHECK-NOT: tail call void @maybe_has_side_effect() - #[unroll(never)] + #[rustc_unroll(never)] for _ in 0..3 { unsafe { maybe_has_side_effect() } } @@ -32,7 +32,7 @@ pub fn unroll_never() { pub fn unroll_count() { // CHECK-LABEL: @unroll_count // CHECK-COUNT-5: tail call void @maybe_has_side_effect() - #[unroll(5)] + #[rustc_unroll(5)] for _ in 0..10 { unsafe { maybe_has_side_effect() } } diff --git a/tests/codegen-llvm/loop-attrs/unroll-loop-metadata.rs b/tests/codegen-llvm/loop-attrs/unroll-loop-metadata.rs index 2b2b0779cf49e..7b715d1ac1e32 100644 --- a/tests/codegen-llvm/loop-attrs/unroll-loop-metadata.rs +++ b/tests/codegen-llvm/loop-attrs/unroll-loop-metadata.rs @@ -17,7 +17,7 @@ pub fn unroll_hint() { // CHECK-LABEL: @unroll_hint // CHECK: !llvm.loop ![[HINT:[0-9]+]] let mut i = 0; - #[unroll] + #[rustc_unroll] loop { unsafe { maybe_has_side_effect() } i += 1; @@ -35,7 +35,7 @@ pub fn unroll_full() { // CHECK-LABEL: @unroll_full // CHECK: !llvm.loop ![[FULL:[0-9]+]] let mut i = 0; - let _return = (#[unroll(full)] + let _return = (#[rustc_unroll(full)] loop { unsafe { maybe_has_side_effect() } i += 1; @@ -50,7 +50,7 @@ pub fn unroll_never() { // CHECK-LABEL: @unroll_never // CHECK: !llvm.loop ![[DISABLE:[0-9]+]] let mut i = 0; - let _return = (1 + #[unroll(never)] + let _return = (1 + #[rustc_unroll(never)] loop { unsafe { maybe_has_side_effect() } i += 1; @@ -65,7 +65,7 @@ pub fn unroll_count() { // CHECK-LABEL: @unroll_count // CHECK: !llvm.loop ![[COUNT:[0-9]+]] let mut i = 0; - #[unroll(5)] + #[rustc_unroll(5)] loop { unsafe { maybe_has_side_effect() } i += 1; diff --git a/tests/codegen-llvm/loop-attrs/unroll-while-metadata.rs b/tests/codegen-llvm/loop-attrs/unroll-while-metadata.rs index c40a4188334e8..1a100aae1e717 100644 --- a/tests/codegen-llvm/loop-attrs/unroll-while-metadata.rs +++ b/tests/codegen-llvm/loop-attrs/unroll-while-metadata.rs @@ -16,7 +16,7 @@ pub fn unroll_hint() { // CHECK-LABEL: @unroll_hint // CHECK: !llvm.loop ![[HINT:[0-9]+]] let mut i = 0; - #[unroll] + #[rustc_unroll] while i < 10 { unsafe { maybe_has_side_effect() } i += 1; @@ -28,7 +28,7 @@ pub fn unroll_full() { // CHECK-LABEL: @unroll_full // CHECK: !llvm.loop ![[FULL:[0-9]+]] let mut i = 0; - #[unroll(full)] + #[rustc_unroll(full)] while i < 10 { unsafe { maybe_has_side_effect() } i += 1; @@ -40,7 +40,7 @@ pub fn unroll_never() { // CHECK-LABEL: @unroll_never // CHECK: !llvm.loop ![[DISABLE:[0-9]+]] let mut i = 0; - #[unroll(never)] + #[rustc_unroll(never)] while i < 10 { unsafe { maybe_has_side_effect() } i += 1; @@ -52,7 +52,7 @@ pub fn unroll_count() { // CHECK-LABEL: @unroll_count // CHECK: !llvm.loop ![[COUNT:[0-9]+]] let mut i = 0; - #[unroll(5)] + #[rustc_unroll(5)] while i < 10 { unsafe { maybe_has_side_effect() } i += 1; diff --git a/tests/ui/attributes/unroll/invalid-unroll.rs b/tests/ui/attributes/unroll/invalid-unroll.rs index 8696cefe818f7..13a14c2713fc1 100644 --- a/tests/ui/attributes/unroll/invalid-unroll.rs +++ b/tests/ui/attributes/unroll/invalid-unroll.rs @@ -2,18 +2,18 @@ #![crate_type = "lib"] pub fn main() { - #[unroll(please)] //~ ERROR malformed `unroll` attribute input + #[rustc_unroll(please)] //~ ERROR malformed `rustc_unroll` attribute input for _ in 0..10 {} - #[unroll("never")] //~ ERROR malformed `unroll` attribute input + #[rustc_unroll("never")] //~ ERROR malformed `rustc_unroll` attribute input for _ in 0..10 {} - #[unroll()] //~ ERROR malformed `unroll` attribute input + #[rustc_unroll()] //~ ERROR malformed `rustc_unroll` attribute input for _ in 0..10 {} - #[unroll(-1)] //~ ERROR expected a literal + #[rustc_unroll(-1)] //~ ERROR expected a literal for _ in 0..10 {} - #[unroll(1.5)] //~ ERROR malformed `unroll` attribute input + #[rustc_unroll(1.5)] //~ ERROR malformed `rustc_unroll` attribute input for _ in 0..10 {} } diff --git a/tests/ui/attributes/unroll/invalid-unroll.stderr b/tests/ui/attributes/unroll/invalid-unroll.stderr index 9d25fa2c42d66..ced0523bf99ea 100644 --- a/tests/ui/attributes/unroll/invalid-unroll.stderr +++ b/tests/ui/attributes/unroll/invalid-unroll.stderr @@ -1,46 +1,46 @@ -error[E0539]: malformed `unroll` attribute input +error[E0539]: malformed `rustc_unroll` attribute input --> $DIR/invalid-unroll.rs:5:7 | -LL | #[unroll(please)] - | ^^^^^^^------^ - | | - | valid arguments are `full` or `never` +LL | #[rustc_unroll(please)] + | ^^^^^^^^^^^^^------^ + | | + | valid arguments are `full` or `never` -error[E0539]: malformed `unroll` attribute input +error[E0539]: malformed `rustc_unroll` attribute input --> $DIR/invalid-unroll.rs:8:7 | -LL | #[unroll("never")] - | ^^^^^^^-------^ - | | - | valid arguments are `full` or `never` +LL | #[rustc_unroll("never")] + | ^^^^^^^^^^^^^-------^ + | | + | valid arguments are `full` or `never` -error[E0805]: malformed `unroll` attribute input +error[E0805]: malformed `rustc_unroll` attribute input --> $DIR/invalid-unroll.rs:11:7 | -LL | #[unroll()] - | ^^^^^^-- - | | - | expected an argument here +LL | #[rustc_unroll()] + | ^^^^^^^^^^^^-- + | | + | expected an argument here error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression - --> $DIR/invalid-unroll.rs:14:14 + --> $DIR/invalid-unroll.rs:14:20 | -LL | #[unroll(-1)] - | ^^ expressions are not allowed here +LL | #[rustc_unroll(-1)] + | ^^ expressions are not allowed here | help: negative numbers are not literals, try removing the `-` sign | -LL - #[unroll(-1)] -LL + #[unroll(1)] +LL - #[rustc_unroll(-1)] +LL + #[rustc_unroll(1)] | -error[E0539]: malformed `unroll` attribute input +error[E0539]: malformed `rustc_unroll` attribute input --> $DIR/invalid-unroll.rs:17:7 | -LL | #[unroll(1.5)] - | ^^^^^^^---^ - | | - | valid arguments are `full` or `never` +LL | #[rustc_unroll(1.5)] + | ^^^^^^^^^^^^^---^ + | | + | valid arguments are `full` or `never` error: aborting due to 5 previous errors diff --git a/tests/ui/borrowck/alias-liveness/gat-static-unnormalized.rs b/tests/ui/borrowck/alias-liveness/gat-static-unnormalized.rs new file mode 100644 index 0000000000000..bb8dfc4553146 --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/gat-static-unnormalized.rs @@ -0,0 +1,47 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for #158461. Outlives clauses from the parameter environment +// need to be normalized before alias liveness analysis can match them. + +trait Id { + type SelfType; +} + +impl Id for T { + type SelfType = T; +} + +trait Foo { + type Assoc<'a> + where + Self: 'a; + + fn assoc(&mut self) -> Self::Assoc<'_>; +} + +// The normalized `'static` bound allows this value's borrow to end immediately. +fn overlapping_mut(mut t: T) +where + T: Foo, + for<'a> as Id>::SelfType: 'static, +{ + let a = t.assoc(); + let b = t.assoc(); +} + +// This is a distinct liveness path: the owner can be moved while the projected +// value remains live. +fn live_past_borrow(mut t: T) +where + T: Foo, + for<'a> as Id>::SelfType: 'static, +{ + let x = t.assoc(); + drop(t); + drop(x); +} + +fn main() {} diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs index f0f9a649165b5..98f79cd8cfc1c 100644 --- a/tests/ui/cfg/cfg-stmt-recovery.rs +++ b/tests/ui/cfg/cfg-stmt-recovery.rs @@ -1,7 +1,7 @@ // Verify that we do not ICE when failing to parse a statement in `cfg_eval`. #![feature(cfg_eval)] -#![feature(stmt_expr_attributes)] +#![feature(stmt_expr_attributes, proc_macro_hygiene)] #[cfg_eval] fn main() { diff --git a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs index 7c42be3ed4d6e..3f6f902cf3688 100644 --- a/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs +++ b/tests/ui/conditional-compilation/invalid-node-range-issue-129166.rs @@ -3,7 +3,7 @@ //@ check-pass #![feature(cfg_eval)] -#![feature(stmt_expr_attributes)] +#![feature(stmt_expr_attributes, proc_macro_hygiene)] fn f() -> u32 { #[cfg_eval] #[cfg(not(FALSE))] 0 diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index bc6c17f463a78..3b28e268662ef 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -8,7 +8,7 @@ #[eii_declaration(bar)] //~ ERROR `#[eii_declaration(...)]` is only valid on macros fn hello() { #[eii_declaration(bar)] //~ ERROR `#[eii_declaration(...)]` is only valid on macros - let x = 3 + 3; + let x = 3 + 3; //~| ERROR custom attributes cannot be applied to statements } #[eii_declaration] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index 553ae622cb36f..512cd135de4c3 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -4,6 +4,16 @@ error: `#[eii_declaration(...)]` is only valid on macros LL | #[eii_declaration(bar)] | ^^^^^^^^^^^^^^^^^^^^^^^ +error[E0658]: custom attributes cannot be applied to statements + --> $DIR/errors.rs:10:5 + | +LL | #[eii_declaration(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #54727 for more information + = help: add `#![feature(proc_macro_hygiene)]` 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: `#[eii_declaration(...)]` is only valid on macros --> $DIR/errors.rs:10:5 | @@ -88,5 +98,6 @@ error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]` LL | #[foo = "default"] | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-loop-hints.rs b/tests/ui/feature-gates/feature-gate-loop-hints.rs index 85a1f10ab0a63..480d9a95f08a9 100644 --- a/tests/ui/feature-gates/feature-gate-loop-hints.rs +++ b/tests/ui/feature-gates/feature-gate-loop-hints.rs @@ -1,4 +1,4 @@ fn main() { - #[unroll] //~ ERROR the `unroll` attribute is an experimental feature + #[rustc_unroll] //~ ERROR the `rustc_unroll` attribute is an experimental feature for _ in 0..10 {} } diff --git a/tests/ui/feature-gates/feature-gate-loop-hints.stderr b/tests/ui/feature-gates/feature-gate-loop-hints.stderr index 98279fe144126..56c3ec6812c9c 100644 --- a/tests/ui/feature-gates/feature-gate-loop-hints.stderr +++ b/tests/ui/feature-gates/feature-gate-loop-hints.stderr @@ -1,8 +1,8 @@ -error[E0658]: the `unroll` attribute is an experimental feature +error[E0658]: the `rustc_unroll` attribute is an experimental feature --> $DIR/feature-gate-loop-hints.rs:2:7 | -LL | #[unroll] - | ^^^^^^ +LL | #[rustc_unroll] + | ^^^^^^^^^^^^ | = note: see issue #156874 for more information = help: add `#![feature(loop_hints)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr index 629d25ec4f01c..884a02c5ec25d 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -33,6 +33,12 @@ error: cannot find attribute `rustc_unknown` in this scope | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[rustc_unknown] +LL + #[rustc_unroll] + | error[E0658]: use of an internal attribute --> $DIR/feature-gate-rustc-attrs.rs:20:3 diff --git a/tests/ui/macros/issue-111749.rs b/tests/ui/macros/issue-111749.rs index f009a69fe2535..799fee22685ab 100644 --- a/tests/ui/macros/issue-111749.rs +++ b/tests/ui/macros/issue-111749.rs @@ -9,4 +9,5 @@ fn main() { //~^ ERROR the `test` attribute may only be used on a free function //~| ERROR attribute must be of the form `#[test]` //~| WARNING this was previously accepted by the compiler but is being phased out + //~| ERROR custom attributes cannot be applied to expressions } diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr index 267f939602b5b..f2773e7029ab5 100644 --- a/tests/ui/macros/issue-111749.stderr +++ b/tests/ui/macros/issue-111749.stderr @@ -1,3 +1,13 @@ +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/issue-111749.rs:8:17 + | +LL | cbor_map! { #[test(test)] 4i32}; + | ^^^^^^^^^^^^^ + | + = note: see issue #54727 for more information + = help: add `#![feature(proc_macro_hygiene)]` 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: the `test` attribute may only be used on a free function --> $DIR/issue-111749.rs:8:17 | @@ -20,8 +30,9 @@ LL | cbor_map! { #[test(test)] 4i32}; = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. Future incompatibility report: Future breakage diagnostic: error: attribute must be of the form `#[test]` --> $DIR/issue-111749.rs:8:17 diff --git a/tests/ui/nll/polonius/nll-legacy-unnecessary-error.legacy.stderr b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.legacy.stderr new file mode 100644 index 0000000000000..79f32e55559cf --- /dev/null +++ b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.legacy.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `z` because it is borrowed + --> $DIR/nll-legacy-unnecessary-error.rs:20:5 + | +LL | x.0 = &z; + | -- `z` is borrowed here +LL | z += 1; + | ^^^^^^ `z` is assigned to here but it was already borrowed +... +LL | dbg!(y.0); + | --- borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/nll/polonius/nll-legacy-unnecessary-error.nll.stderr b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.nll.stderr new file mode 100644 index 0000000000000..79f32e55559cf --- /dev/null +++ b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.nll.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `z` because it is borrowed + --> $DIR/nll-legacy-unnecessary-error.rs:20:5 + | +LL | x.0 = &z; + | -- `z` is borrowed here +LL | z += 1; + | ^^^^^^ `z` is assigned to here but it was already borrowed +... +LL | dbg!(y.0); + | --- borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/nll/polonius/nll-legacy-unnecessary-error.rs b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.rs new file mode 100644 index 0000000000000..06a4f9b1a5640 --- /dev/null +++ b/tests/ui/nll/polonius/nll-legacy-unnecessary-error.rs @@ -0,0 +1,25 @@ +// NLLs and legacy polonius emit an unnecessary error here, unlike the alpha. It's not clear +// *exactly* why the datalog implementation rejects this, but it looks like it propagates the loan +// from 'x to 'y very eagerly, even though x is dead before the assignment. The loan would thus be +// live and invalidated by the assignment, AKA an error. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius legacy +//@ [nll] compile-flags: -Z polonius=off +//@ [polonius] check-pass +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy + +fn main() { + let mut x: (&u32,) = (&1,); + let mut y: (&u32,) = (&2,); + let mut z = 3; + + y.0 = x.0; + x.0 = &z; + z += 1; + //[nll]~^ ERROR: cannot assign to `z` because it is borrowed + //[legacy]~^^ ERROR: cannot assign to `z` because it is borrowed + + dbg!(y.0); +} diff --git a/tests/ui/parser/brace-in-let-chain.stderr b/tests/ui/parser/brace-in-let-chain.stderr index 12af95c278688..15622bd3266b2 100644 --- a/tests/ui/parser/brace-in-let-chain.stderr +++ b/tests/ui/parser/brace-in-let-chain.stderr @@ -4,24 +4,46 @@ error: this file contains an unclosed delimiter LL | fn main() { | - unclosed delimiter ... +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... LL | fn quux() { | - unclosed delimiter ... +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... LL | fn foobar() { | - unclosed delimiter ... +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... LL | fn fubar() { | - unclosed delimiter ... +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... LL | fn qux() { | - unclosed delimiter ... +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... LL | fn foo() { | - another 3 unclosed delimiters begin from here +LL | { +LL | && let () = () + | -- you might have meant to continue an if-let chain here +... +LL | && let () = () + | -- you might have meant to continue an if-let chain here ... LL | { | - this delimiter might not be properly closed... LL | && let () = () + | -- you might have meant to continue an if-let chain here LL | } | - ...as it matches this but it has different indentation LL | } diff --git a/tests/ui/parser/deli-ident-issue-1.stderr b/tests/ui/parser/deli-ident-issue-1.stderr index d17913eb7ea40..7abe8b0ea5554 100644 --- a/tests/ui/parser/deli-ident-issue-1.stderr +++ b/tests/ui/parser/deli-ident-issue-1.stderr @@ -6,7 +6,9 @@ LL | impl dyn Demo { ... LL | && let Some(c) = num { | - this delimiter might not be properly closed... -... +LL | && b == c { + | -- you might have meant to continue an if-let chain here +LL | } LL | } | - ...as it matches this but it has different indentation ... diff --git a/tests/ui/parser/if-let-chain-unclosed-delim.rs b/tests/ui/parser/if-let-chain-unclosed-delim.rs new file mode 100644 index 0000000000000..11f365ce5311c --- /dev/null +++ b/tests/ui/parser/if-let-chain-unclosed-delim.rs @@ -0,0 +1,8 @@ +//! Regression test for an unclosed delimiter whose block begins with `&&`/`||` +//! should hint that the user may have meant to continue an if-let chain. +fn main() { + if let Some(x) = Some(42) { + && x == 42 + { + } +} //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/if-let-chain-unclosed-delim.stderr b/tests/ui/parser/if-let-chain-unclosed-delim.stderr new file mode 100644 index 0000000000000..ce34a89b62b5a --- /dev/null +++ b/tests/ui/parser/if-let-chain-unclosed-delim.stderr @@ -0,0 +1,17 @@ +error: this file contains an unclosed delimiter + --> $DIR/if-let-chain-unclosed-delim.rs:8:54 + | +LL | fn main() { + | - unclosed delimiter +LL | if let Some(x) = Some(42) { + | - this delimiter might not be properly closed... +LL | && x == 42 + | -- you might have meant to continue an if-let chain here +... +LL | } + | - ^ + | | + | ...as it matches this but it has different indentation + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.rs b/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.rs new file mode 100644 index 0000000000000..e0088837fac8e --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.rs @@ -0,0 +1,6 @@ +//! Regression test for . + +fn main() { + drop::<[(), 0]>([]); + //~^ ERROR expected `;` or `]`, found `,` +} diff --git a/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.stderr b/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.stderr new file mode 100644 index 0000000000000..17dc812c8e6ec --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi-turbofish-81097.stderr @@ -0,0 +1,14 @@ +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi-turbofish-81097.rs:4:15 + | +LL | drop::<[(), 0]>([]); + | ^ expected `;` or `]` + | +help: you might have meant to use `;` as the separator + | +LL - drop::<[(), 0]>([]); +LL + drop::<[(); 0]>([]); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/cfg-eval-fail.rs b/tests/ui/proc-macro/cfg-eval-fail.rs index a94dcd2837811..2cde895f2ea44 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.rs +++ b/tests/ui/proc-macro/cfg-eval-fail.rs @@ -4,4 +4,5 @@ fn main() { let _ = #[cfg_eval] #[cfg(false)] 0; //~^ ERROR removing an expression is not supported in this position + //~| ERROR custom attributes cannot be applied to expressions } diff --git a/tests/ui/proc-macro/cfg-eval-fail.stderr b/tests/ui/proc-macro/cfg-eval-fail.stderr index 7f21e4646b1cc..61da346fa69f6 100644 --- a/tests/ui/proc-macro/cfg-eval-fail.stderr +++ b/tests/ui/proc-macro/cfg-eval-fail.stderr @@ -4,5 +4,16 @@ error: removing an expression is not supported in this position LL | let _ = #[cfg_eval] #[cfg(false)] 0; | ^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/cfg-eval-fail.rs:5:13 + | +LL | let _ = #[cfg_eval] #[cfg(false)] 0; + | ^^^^^^^^^^^ + | + = note: see issue #54727 for more information + = help: add `#![feature(proc_macro_hygiene)]` 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 2 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/proc-macro/derive-macro-invalid-placement.rs b/tests/ui/proc-macro/derive-macro-invalid-placement.rs index fd24bd7284a92..463e7dc758505 100644 --- a/tests/ui/proc-macro/derive-macro-invalid-placement.rs +++ b/tests/ui/proc-macro/derive-macro-invalid-placement.rs @@ -1,6 +1,6 @@ //! regression test for -#![feature(stmt_expr_attributes)] +#![feature(stmt_expr_attributes, proc_macro_hygiene)] fn foo<#[derive(Debug)] T>() { //~ ERROR expected non-macro attribute, found attribute macro match 0 { diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-multiple-reexports.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-multiple-reexports.rs new file mode 100644 index 0000000000000..8ff8d3b572741 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-multiple-reexports.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +extern crate transitive_dep; + +mod private { + pub use crate::transitive_dep::Struct; +} + +#[doc(hidden)] +pub use crate::private::*; + +#[doc(hidden)] +pub mod __private { + pub use crate::private::*; +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.rs new file mode 100644 index 0000000000000..c3ec780429376 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.rs @@ -0,0 +1,16 @@ +//@ aux-build: transitive-dep.rs +//@ aux-build: direct-dep-with-multiple-reexports.rs + +extern crate direct_dep_with_multiple_reexports as direct_dep; + +struct Struct; +//~^ NOTE `Struct` is defined in the current crate + +fn main() { + let _: direct_dep::Struct = Struct; + //~^ ERROR mismatched types + //~| NOTE expected `direct_dep::Struct`, found `Struct` + //~| NOTE expected due to this + //~| NOTE `Struct` and `direct_dep::Struct` have similar names, but are actually distinct types + //~| NOTE `direct_dep::Struct` is defined in crate `transitive_dep` +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.stderr b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.stderr new file mode 100644 index 0000000000000..46042907b38d7 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/use-shortest-hidden-reexport-path.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/use-shortest-hidden-reexport-path.rs:10:33 + | +LL | let _: direct_dep::Struct = Struct; + | ------------------ ^^^^^^ expected `direct_dep::Struct`, found `Struct` + | | + | expected due to this + | + = note: `Struct` and `direct_dep::Struct` have similar names, but are actually distinct types +note: `Struct` is defined in the current crate + --> $DIR/use-shortest-hidden-reexport-path.rs:6:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +note: `direct_dep::Struct` is defined in crate `transitive_dep` + --> $DIR/auxiliary/transitive-dep.rs:3:1 + | +LL | pub struct Struct; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/next-solver/generalize/eagerly-normalizing-aliases.rs b/tests/ui/traits/next-solver/generalize/eagerly-normalizing-aliases.rs new file mode 100644 index 0000000000000..2d5ae9d21010f --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/eagerly-normalizing-aliases.rs @@ -0,0 +1,31 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for trait-system-refactor-initiative#262. + +trait View {} + +trait HasAssoc { + type Assoc; +} + +struct StableVec(T); + +impl View for StableVec {} + +fn assert_view(f: F) -> F { + f +} + +fn store() -> StableVec +where + T: HasAssoc, + StableVec: View, +{ + let x = todo!(); + assert_view(x) +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.rs b/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.rs new file mode 100644 index 0000000000000..f93410550bdcf --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#267. This recursively +// changing opaque type used to overflow the stack while instantiating a +// canonical response. + +trait Distribution {} + +impl Distribution<(A, B)> for u32 +where + u32: Distribution, + u32: Distribution, +{ +} + +fn require_distribution, T>(_: *mut T) {} + +fn random_paulis() -> Option<*mut impl Sized> { + if false { + let r = random_paulis().unwrap(); + //~^ ERROR type annotations needed + require_distribution::(r); + } + + None +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.stderr b/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.stderr new file mode 100644 index 0000000000000..b3b173def6a01 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/recursive-hidden-type-canonicalization.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `*mut _` + --> $DIR/recursive-hidden-type-canonicalization.rs:20:13 + | +LL | let r = random_paulis().unwrap(); + | ^ + | +help: consider giving `r` an explicit type, where the placeholder `_` is specified + | +LL | let r: *mut _ = random_paulis().unwrap(); + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/opaques/stalled-goal-rerun.rs b/tests/ui/traits/next-solver/opaques/stalled-goal-rerun.rs new file mode 100644 index 0000000000000..8402d695749cd --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/stalled-goal-rerun.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#267. This used to hang +// because a fast-path goal was not rerun after the opaque type storage changed. + +trait Distribution {} + +impl Distribution<()> for u32 {} + +impl Distribution<(A, B)> for u32 +where + u32: Distribution, + u32: Distribution, +{ +} + +trait Trait { + type Item; +} + +impl Trait for Option +where + u32: Distribution, +{ + type Item = T; +} + +fn random_paulis() -> impl Trait { + None +} + +fn main() {}