diff --git a/.mailmap b/.mailmap index 3fc567081c1ff..d1e5b3f519591 100644 --- a/.mailmap +++ b/.mailmap @@ -491,6 +491,7 @@ Milan Landaverde mjptree Ms2ger msizanoen1 +mu001999 Mukilan Thiagarajan Nadrieril Feneanar Nadrieril Feneanar diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 733a1956231b1..7b68fbc9e77b0 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1498,19 +1498,21 @@ where // Compute the size and alignment of the vector let size = elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; - let (repr, align) = match kind { + let (repr, size, align) = match kind { SimdVectorKind::Scalable(number_of_vectors) => ( BackendRepr::SimdScalableVector { element, count, number_of_vectors }, + size.checked_mul(number_of_vectors.0 as u64, dl) + .ok_or_else(|| LayoutCalculatorError::SizeOverflow)?, dl.llvmlike_vector_align(size), ), // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. SimdVectorKind::PackedFixed if !count.is_power_of_two() => { - (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) + (BackendRepr::Memory { sized: true }, size, Align::max_aligned_factor(size)) } SimdVectorKind::PackedFixed | SimdVectorKind::Fixed => { - (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size)) + (BackendRepr::SimdVector { element, count }, size, dl.llvmlike_vector_align(size)) } }; let size = size.align_to(align); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 47d3a1249c846..3e754c33cad6a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -104,7 +104,7 @@ pub fn parse_cfg_entry( Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?, _ => { let mut possibilities = vec![sym::any, sym::all, sym::not, sym::target]; - if cx.features().cfg_version() { + if cx.features_option().is_some_and(Features::cfg_version) { possibilities.push(sym::version); } return Err(cx.adcx().expected_specific_argument(meta.span(), &possibilities)); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f1a22fd6af982..caa566e79e29b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,6 +15,7 @@ use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{ CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr, }; +use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::{ @@ -28,7 +29,7 @@ use rustc_middle::ty::{ self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, suggest_constraining_type_params, }; -use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; +use rustc_mir_dataflow::move_paths::{Init, InitKind, InitLocation, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, ExpnKind, Ident, MacroKind, Span, Symbol, kw, sym}; @@ -110,6 +111,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { used_place, moved_place, desired_action, + location, span, use_spans, ); @@ -769,12 +771,61 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + /// Returns `true` if the given initialization can reach the error location. + /// + /// This is used to determine whether an initialization should be considered + /// when reporting diagnostics at `err_location`. + /// + /// The check proceeds in two stages: + /// + /// 1. If the initialization originates from a function argument, it is + /// considered reachable by definition. + /// 2. If the initialization's basic block dominates the error block, then + /// every path to the error must pass through the initialization, so it is + /// reachable. + /// 3. Otherwise, perform a graph traversal over the MIR control-flow graph to + /// determine whether any path exists from the initialization block to the + /// error block. + /// + /// The dominance check acts as a fast path for the common case, while the CFG + /// traversal handles cases where the initialization does not dominate the + /// error location but can still reach it through an alternate control-flow + /// path. + fn is_init_reachable(&self, init: &Init, err_location: mir::Location) -> bool { + let dominators = self.body.basic_blocks.dominators(); + let init_block = match init.location { + InitLocation::Argument(_) => return true, + InitLocation::Statement(location) => location.block, + }; + let err_block = err_location.block; + if dominators.dominates(init_block, err_block) { + return true; + } + // If init_block doesn't dominate error_block, check if there is any valid path from the + // initialization block to the error block in the Control Flow Graph. + let mut visited = DenseBitSet::new_empty(self.body.basic_blocks.len()); + let mut stack = vec![init_block]; + while let Some(block) = stack.pop() { + if block == err_block { + return true; + } + if visited.insert(block) { + let data = &self.body.basic_blocks[block]; + for successor in data.terminator().successors() { + stack.push(successor); + } + } + } + false + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, used_place: PlaceRef<'tcx>, moved_place: PlaceRef<'tcx>, desired_action: InitializationRequiringAction, + location: Location, span: Span, use_spans: UseSpans<'tcx>, ) -> Diag<'infcx> { @@ -783,15 +834,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let inits = &self.move_data.init_path_map[mpi]; let move_path = &self.move_data.move_paths[mpi]; let decl_span = self.body.local_decls[move_path.place.local].source_info.span; - let mut spans_set = FxIndexSet::default(); + let mut all_init_spans_set = FxIndexSet::default(); + let mut reachable_spans_set = FxIndexSet::default(); for init_idx in inits { let init = &self.move_data.inits[*init_idx]; let span = init.span(self.body); if !span.is_dummy() { - spans_set.insert(span); + all_init_spans_set.insert(span); + if self.is_init_reachable(init, location) { + reachable_spans_set.insert(span); + } } } - let spans: Vec<_> = spans_set.into_iter().collect(); + let all_init_spans: Vec<_> = all_init_spans_set.into_iter().collect(); + let reachable_spans: Vec<_> = reachable_spans_set.into_iter().collect(); let (name, desc) = match self.describe_place_with_options( moved_place, @@ -812,9 +868,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // for the branching codepaths that aren't covered, to point at them. let tcx = self.infcx.tcx; let body = tcx.hir_body_owned_by(self.mir_def_id()); - let mut visitor = ConditionVisitor { tcx, spans, name, errors: vec![] }; + let mut visitor = + ConditionVisitor { tcx, spans: all_init_spans.clone(), name, errors: vec![] }; visitor.visit_body(&body); - let spans = visitor.spans; let mut show_assign_sugg = false; let isnt_initialized = if let InitializationRequiringAction::PartialAssignment @@ -824,7 +880,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // that are *partially* initialized by assigning to a field of an uninitialized // binding. We differentiate between them for more accurate wording here. "isn't fully initialized" - } else if !spans.iter().any(|i| { + } else if !reachable_spans.iter().any(|i| { // We filter these to avoid misleading wording in cases like the following, // where `x` has an `init`, but it is in the same place we're looking at: // ``` @@ -840,7 +896,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .any(|sp| span < sp && !sp.contains(span)) }) { show_assign_sugg = true; - "isn't initialized" + if all_init_spans.iter().any(|init_span| !init_span.contains(span)) + && reachable_spans.is_empty() + { + "isn't initialized on any path leading to this point" + } else { + "isn't initialized" + } } else { "is possibly-uninitialized" }; @@ -887,7 +949,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } if !shown { - for sp in &spans { + for sp in &reachable_spans { if *sp < span && !sp.overlaps(span) { err.span_label(*sp, "binding initialized here in some conditions"); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 31131bc889d57..e6b8c537d8451 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1512,7 +1512,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } // FIXME implement variadics in cranelift - sym::va_arg | sym::va_end => { + sym::va_arg => { fx.tcx.dcx().span_fatal( source_info.span, "Defining variadic functions is not yet supported by Cranelift", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 728cd90cf637d..a12116d5b9d39 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -705,10 +705,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc unimplemented!(); } - fn va_end(&mut self, _va_list: RValue<'gcc>) { - // FIXME(antoyo): implement. - } - fn retag_reg(&mut self, _ptr: Self::Value, _info: &RetagInfo) -> Self::Value { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 4d18818bbe7bd..bdaf72cb17ce6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -725,7 +725,7 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm: }, CanonAbi::RustTail => match &sess.target.arch { Arch::X86 | Arch::X86_64 | Arch::AArch64 => llvm::Tail, - _ => sess.dcx().fatal("extern \"tail\" is only supported on x86_64 and aarch64"), + _ => sess.dcx().fatal("extern \"tail\" is only supported on x86, x86_64 and aarch64"), }, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 393837375769e..0b03d6862ca84 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1070,10 +1070,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list]); } - fn va_end(&mut self, va_list: &'ll Value) { - self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list]); - } - fn retag_reg(&mut self, ptr: Self::Value, info: &RetagInfo) -> Self::Value { codegen_retag_inner(self, "__rust_retag_reg", ptr, info) } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 0276e0433cd4e..7fe57fc7adb75 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -525,13 +525,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn codegen_return_terminator(&mut self, bx: &mut Bx) { - // Call `va_end` if this is the definition of a C-variadic function. + // Explicitly end the lifetime of the VaList if this function is c-variadic. We explicitly + // start the lifetime when desugaring `...`. Ending the lifetime meaningfully improves + // codegen. if self.fn_abi.c_variadic { // The `VaList` "spoofed" argument is just after all the real arguments. let va_list_arg_idx = self.fn_abi.args.len(); match self.locals[mir::Local::arg(va_list_arg_idx)] { LocalRef::Place(va_list) => { - bx.va_end(va_list.val.llval); + // NOTE: we don't actually call LLVM's va_end here. We know it's a no-op for + // all current targets and hence don't bother + // (as permitted by https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic). // Explicitly end the lifetime of the `va_list`, improves LLVM codegen. bx.lifetime_end(va_list.val.llval, va_list.layout.size); diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index dcd4e722a27a8..47144834b5072 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -52,9 +52,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { /// Trait method used to inject `va_start` on the "spoofed" `VaList` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value); - /// Trait method used to inject `va_end` on the "spoofed" `VaList` before - /// Rust defined C-variadic functions return. - fn va_end(&mut self, val: Self::Value); /// Trait method used to retag a pointer stored within a place. fn retag_mem(&mut self, place: Self::Value, info: &RetagInfo); /// Trait method used to retag a pointer that has been loaded into a register. diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index 4067161d93d72..c80c63b7c0188 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -1,10 +1,8 @@ -use std::iter; - use GenericArgsInfo::*; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir as hir; -use rustc_middle::ty::{self as ty, AssocItems, TyCtxt}; +use rustc_middle::ty::{self as ty, AssocItem, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; use tracing::debug; @@ -485,13 +483,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .collect() } - fn get_unbound_associated_types(&self) -> Vec { + fn get_unbound_associated_item(&self) -> Vec<&AssocItem> { if self.tcx.is_trait(self.def_id) { let items: &AssocItems = self.tcx.associated_items(self.def_id); items .in_definition_order() .filter(|item| { - item.is_type() + (item.is_type() || item.is_type_const()) && !item.is_impl_trait_in_trait() && !self .gen_args @@ -499,7 +497,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .iter() .any(|constraint| constraint.ident.name == item.name()) }) - .map(|item| self.tcx.item_ident(item.def_id).to_string()) .collect() } else { Vec::default() @@ -905,7 +902,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); - let unbound_types = self.get_unbound_associated_types(); + let unbound_assoc_items = self.get_unbound_associated_item(); let num_provided_args = num_provided_lt_args + num_provided_type_const_args; assert!(num_provided_args > 0); @@ -917,8 +914,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let redundant_type_or_const_args = num_redundant_type_or_const_args > 0; let remove_entire_generics = num_redundant_args >= self.gen_args.args.len(); - let provided_args_matches_unbound_traits = - unbound_types.len() == num_redundant_type_or_const_args; let remove_lifetime_args = |err: &mut Diag<'_, _>| { let mut lt_arg_spans = Vec::new(); @@ -1012,24 +1007,41 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); }; - // If there is a single unbound associated type and a single excess generic param - // suggest replacing the generic param with the associated type bound - if provided_args_matches_unbound_traits && !unbound_types.is_empty() { + // If there is an identical amount of unbound associated items and excess generic args + // suggest turning the generic args into associated item bindings + if unbound_assoc_items.len() == num_redundant_type_or_const_args + && !unbound_assoc_items.is_empty() + { // Don't suggest if we're in a trait impl as // that would result in invalid syntax (fixes #116464) if !self.is_in_trait_impl() { let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - let suggestions = iter::zip(unused_generics, &unbound_types) - .map(|(potential, name)| { - (potential.span().shrink_to_lo(), format!("{name} = ")) + let mut unbound_assoc_consts = + unbound_assoc_items.iter().filter(|item| item.is_type_const()); + let mut unbound_assoc_types = + unbound_assoc_items.iter().filter(|item| item.is_type()); + let suggestions = unused_generics + .iter() + .filter_map(|potential| { + let item = match potential { + hir::GenericArg::Const(_) => unbound_assoc_consts.next(), + hir::GenericArg::Type(_) => unbound_assoc_types.next(), + _ => None, + }?; + Some(( + potential.span().shrink_to_lo(), + // FIXME: This doesn't account for generic associated items + format!("{} = ", self.tcx.item_ident(item.def_id)), + )) }) .collect::>(); if !suggestions.is_empty() { + let s = pluralize!(suggestions.len()); + let article = if suggestions.len() == 1 { "an " } else { "" }; err.multipart_suggestion( format!( - "replace the generic bound{s} with the associated type{s}", - s = pluralize!(unbound_types.len()) + "turn the generic argument{s} into {article}associated item binding{s}" ), suggestions, Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 7c934b2d16751..73be0d9a02f3e 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -937,21 +937,28 @@ impl EarlyLintPass for UnusedParens { && !dyn2015_exception { let s = poly_trait_ref.span; - let spans = (!s.from_expansion()).then(|| { - ( + // Check that the span really is wrapped in single-byte ASCII parens + // before trimming a byte off each end, in case a macro does weird + // things with spans or parser recovery produced multibyte parens. + if !s.from_expansion() + && let Ok(snippet) = cx.sess().source_map().span_to_snippet(s) + && snippet.starts_with('(') + && snippet.ends_with(')') + { + let spans = Some(( 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.emit_unused_delims( + cx, + poly_trait_ref.span, + spans, + "type", + (false, false), + false, + ); + } } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 178f79173ea50..0324ba8723a24 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -12,7 +12,9 @@ use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::span_bug; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, Unnormalized, +}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::ObligationCause; @@ -106,72 +108,92 @@ impl<'tcx> ConstToPat<'tcx> { self.tcx.erase_and_anonymize_regions(self.typing_env).with_codegen_normalized(self.tcx); let uv = self.tcx.erase_and_anonymize_regions(uv); - // try to resolve e.g. associated constants to their definition on an impl, and then - // evaluate the const. - let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) { - Ok(Ok(c)) => c, - Err(ErrorHandled::Reported(_, _)) => { - // Let's tell the use where this failing const occurs. - let mut err = - self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span }); - // We've emitted an error on the original const, it would be redundant to complain - // on its use as well. - if let ty::ConstKind::Unevaluated(uv) = self.c.kind() - && let ty::UnevaluatedConstKind::Projection { .. } - | ty::UnevaluatedConstKind::Inherent { .. } - | ty::UnevaluatedConstKind::Free { .. } = uv.kind - { - err.downgrade_to_delayed_bug(); - } + // FIXME(gca): This will become insufficient once associated constants can be + // implemented as `type` consts (project-const-generics#76). At that point it'll + // become necessary to just use type system normalization for all const patterns + // but that's not yet possible. + let mut thir_pat = if uv.kind.is_type_const(self.tcx) { + let Ok(normalize) = self + .tcx + .try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c)) + else { + let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span }); return self.mk_err(err, ty); - } - Err(ErrorHandled::TooGeneric(_)) => { - let mut e = self - .tcx - .dcx() - .create_err(ConstPatternDependsOnGenericParameter { span: self.span }); - for arg in uv.args { - if let ty::GenericArgKind::Type(ty) = arg.kind() - && let ty::Param(param_ty) = ty.kind() + }; + + let ty::ConstKind::Value(value) = normalize.kind() else { + let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span }); + return self.mk_err(err, ty); + }; + self.valtree_to_pat(value) + } else { + // try to resolve e.g. associated constants to their definition on an impl, and then + // evaluate the const. + let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) { + Ok(Ok(c)) => c, + Err(ErrorHandled::Reported(_, _)) => { + // Let's tell the use where this failing const occurs. + let mut err = + self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span }); + // We've emitted an error on the original const, it would be redundant to complain + // on its use as well. + if let ty::ConstKind::Unevaluated(uv) = self.c.kind() + && let ty::UnevaluatedConstKind::Projection { .. } + | ty::UnevaluatedConstKind::Inherent { .. } + | ty::UnevaluatedConstKind::Free { .. } = uv.kind { - let def_id = self.tcx.hir_enclosing_body_owner(self.id); - let generics = self.tcx.generics_of(def_id); - let param = generics.type_param(*param_ty, self.tcx); - let span = self.tcx.def_span(param.def_id); - e.span_label(span, "constant depends on this generic parameter"); - if let Some(ident) = self.tcx.def_ident_span(def_id) - && self.tcx.sess.source_map().is_multiline(ident.between(span)) + err.downgrade_to_delayed_bug(); + } + return self.mk_err(err, ty); + } + Err(ErrorHandled::TooGeneric(_)) => { + let mut e = self + .tcx + .dcx() + .create_err(ConstPatternDependsOnGenericParameter { span: self.span }); + for arg in uv.args { + if let ty::GenericArgKind::Type(ty) = arg.kind() + && let ty::Param(param_ty) = ty.kind() { - // Display the `fn` name as well in the diagnostic, as the generic isn't - // in the same line and it could be confusing otherwise. - e.span_label(ident, ""); + let def_id = self.tcx.hir_enclosing_body_owner(self.id); + let generics = self.tcx.generics_of(def_id); + let param = generics.type_param(*param_ty, self.tcx); + let span = self.tcx.def_span(param.def_id); + e.span_label(span, "constant depends on this generic parameter"); + if let Some(ident) = self.tcx.def_ident_span(def_id) + && self.tcx.sess.source_map().is_multiline(ident.between(span)) + { + // Display the `fn` name as well in the diagnostic, as the generic isn't + // in the same line and it could be confusing otherwise. + e.span_label(ident, ""); + } } } + return self.mk_err(e, ty); } - return self.mk_err(e, ty); - } - Ok(Err(bad_ty)) => { - // The pattern cannot be turned into a valtree. - let e = match bad_ty.kind() { - ty::Adt(def, ..) => { - assert!(def.is_union()); - self.tcx.dcx().create_err(UnionPattern { span: self.span }) - } - ty::FnPtr(..) | ty::RawPtr(..) => { - self.tcx.dcx().create_err(PointerPattern { span: self.span }) - } - _ => self.tcx.dcx().create_err(InvalidPattern { - span: self.span, - non_sm_ty: bad_ty, - prefix: bad_ty.prefix_string(self.tcx).to_string(), - }), - }; - return self.mk_err(e, ty); - } - }; + Ok(Err(bad_ty)) => { + // The pattern cannot be turned into a valtree. + let e = match bad_ty.kind() { + ty::Adt(def, ..) => { + assert!(def.is_union()); + self.tcx.dcx().create_err(UnionPattern { span: self.span }) + } + ty::FnPtr(..) | ty::RawPtr(..) => { + self.tcx.dcx().create_err(PointerPattern { span: self.span }) + } + _ => self.tcx.dcx().create_err(InvalidPattern { + span: self.span, + non_sm_ty: bad_ty, + prefix: bad_ty.prefix_string(self.tcx).to_string(), + }), + }; + return self.mk_err(e, ty); + } + }; - // Lower the valtree to a THIR pattern. - let mut thir_pat = self.valtree_to_pat(ty::Value { ty, valtree }); + // Lower the valtree to a THIR pattern. + self.valtree_to_pat(ty::Value { ty, valtree }) + }; if !thir_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index b3f7efb4d7cf7..7e1eafa10097f 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -755,7 +755,10 @@ impl<'a, Ty> FnAbi<'a, Ty> { if arg_idx.is_none() && arg.layout.size > Primitive::Pointer(AddressSpace::ZERO).size(cx) * 2 - && !matches!(arg.layout.backend_repr, BackendRepr::SimdVector { .. }) + && !matches!( + arg.layout.backend_repr, + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } + ) { // Return values larger than 2 registers using a return area // pointer. LLVM and Cranelift disagree about how to return diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index f7573c7d7fc3e..f7feb3bbbca85 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -9,7 +9,6 @@ #![feature(downcast_unchecked)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] -#![feature(int_format_into)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] #![feature(pattern)] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c4bab254c146c..08781532a0919 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -36,8 +36,10 @@ pub enum Alignment { Center, } -#[unstable(feature = "int_format_into", issue = "138215")] -pub use num_buffer::{NumBuffer, NumBufferTrait}; +#[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] +pub use num_buffer::NumBuffer; +#[unstable(feature = "fmt_internals", issue = "none")] +pub use num_buffer::NumBufferTrait; #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 309aee53f93c7..013abab412a9d 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -260,7 +260,6 @@ macro_rules! impl_Display { /// # Examples /// /// ``` - /// #![feature(int_format_into)] /// use core::fmt::NumBuffer; /// #[doc = concat!("let n = 0", stringify!($Signed), ";")] @@ -273,7 +272,7 @@ macro_rules! impl_Display { #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")] #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")] /// ``` - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub fn format_into(self, buf: &mut NumBuffer) -> &str { let mut offset; @@ -305,7 +304,6 @@ macro_rules! impl_Display { /// # Examples /// /// ``` - /// #![feature(int_format_into)] /// use core::fmt::NumBuffer; /// #[doc = concat!("let n = 0", stringify!($Unsigned), ";")] @@ -318,7 +316,7 @@ macro_rules! impl_Display { #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")] #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")] /// ``` - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub fn format_into(self, buf: &mut NumBuffer) -> &str { let offset; @@ -744,7 +742,6 @@ impl u128 { /// # Examples /// /// ``` - /// #![feature(int_format_into)] /// use core::fmt::NumBuffer; /// /// let n = 0u128; @@ -759,7 +756,7 @@ impl u128 { /// let mut buf2 = NumBuffer::new(); /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string()); /// ``` - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub fn format_into(self, buf: &mut NumBuffer) -> &str { let diff = buf.capacity() - U128_MAX_DEC_N; // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const @@ -779,7 +776,6 @@ impl i128 { /// # Examples /// /// ``` - /// #![feature(int_format_into)] /// use core::fmt::NumBuffer; /// /// let n = 0i128; @@ -792,7 +788,7 @@ impl i128 { /// let n2 = i128::MAX; /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string()); /// ``` - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub fn format_into(self, buf: &mut NumBuffer) -> &str { let diff = buf.capacity() - U128_MAX_DEC_N; // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const diff --git a/library/core/src/fmt/num_buffer.rs b/library/core/src/fmt/num_buffer.rs index cc3680b8a42be..4fbdd1fcd2163 100644 --- a/library/core/src/fmt/num_buffer.rs +++ b/library/core/src/fmt/num_buffer.rs @@ -1,21 +1,22 @@ use crate::mem::MaybeUninit; /// Trait used to describe the maximum number of digits in decimal base of the implemented integer. -#[unstable(feature = "int_format_into", issue = "138215")] +#[unstable(feature = "fmt_internals", issue = "none")] pub trait NumBufferTrait { /// Maximum number of digits in decimal base of the implemented integer. + #[unstable(feature = "fmt_internals", issue = "none")] const BUF_SIZE: usize; } macro_rules! impl_NumBufferTrait { ($($signed:ident, $unsigned:ident,)*) => { $( - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] impl NumBufferTrait for $signed { // `+ 2` and not `+ 1` to include the `-` character. const BUF_SIZE: usize = $signed::MAX.ilog(10) as usize + 2; } - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] impl NumBufferTrait for $unsigned { const BUF_SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; } @@ -38,7 +39,6 @@ impl_NumBufferTrait! { /// # Examples /// /// ``` -/// #![feature(int_format_into)] /// use core::fmt::NumBuffer; /// /// let mut buf = NumBuffer::new(); @@ -50,7 +50,7 @@ impl_NumBufferTrait! { /// let n2 = -1972i32; /// assert_eq!(n2.format_into(&mut buf), "-1972"); /// ``` -#[unstable(feature = "int_format_into", issue = "138215")] +#[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub struct NumBuffer { // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40. pub(crate) buf: [MaybeUninit; 40], @@ -58,25 +58,24 @@ pub struct NumBuffer { phantom: core::marker::PhantomData, } -#[unstable(feature = "int_format_into", issue = "138215")] +#[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] impl core::fmt::Debug for NumBuffer { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("NumBuffer").finish() } } -#[unstable(feature = "int_format_into", issue = "138215")] +#[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] impl NumBuffer { /// Initializes internal buffer. - #[unstable(feature = "int_format_into", issue = "138215")] + #[stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_format_into", since = "CURRENT_RUSTC_VERSION")] pub const fn new() -> Self { // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40. NumBuffer { buf: [MaybeUninit::::uninit(); 40], phantom: core::marker::PhantomData } } - /// Returns the length of the internal buffer. - #[unstable(feature = "int_format_into", issue = "138215")] - pub const fn capacity(&self) -> usize { + pub(crate) const fn capacity(&self) -> usize { self.buf.len() } } diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 4616c3dc4a373..a70cb8ad67297 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -43,13 +43,63 @@ use crate::ptr; /// } /// ``` /// -/// # Interaction with `Box` +/// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. +/// +/// Special care is needed when all of the conditions below are met: +/// * A struct or enum contains a `ManuallyDrop`. +/// * The `ManuallyDrop` is not inside a `union`. +/// * The struct or enum is part of public API, or is stored in a struct or an +/// enum that is part of public API. +/// * There is a _safe_ function that drops the contents of the `ManuallyDrop` +/// field, and it can be called outside the struct or enum's `Drop` implementation. +/// +/// In particular, deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, +/// or `Hash` on the struct or enum could be unsound, since the derived +/// implementations of these traits would access the `ManuallyDrop` field. +/// +/// For example, in the following code, `derive(Debug)` is unsound in combination +/// with the `ManuallyDrop::drop` call in `Foo::new`: +/// +/// ```no_run +/// # use std::mem::ManuallyDrop; +/// #[derive(Debug)] +/// pub struct Foo { +/// /// Invariant: this value may have been dropped! +/// value: ManuallyDrop, +/// } +/// impl Foo { +/// pub fn new() -> Self { +/// let mut temp = Self { +/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) +/// }; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet. +/// ManuallyDrop::drop(&mut temp.value); +/// } +/// temp +/// } +/// } +/// ``` +/// +/// As one could use the `Debug` implementation to access an already dropped +/// field: +/// +/// ```rust,ignore (uses-type-from-separate-snippet) +/// let foo = Foo::new(); +/// println!("{foo:?}"); // Undefined behavior! +/// ``` /// -/// Currently, if you have a `ManuallyDrop`, where the type `T` is a `Box` or -/// contains a `Box` inside, then dropping the `T` followed by moving the -/// `ManuallyDrop` is [considered to be undefined +/// Note that similar unsoundness can arise without `derive`. The cause of the +/// unsoundness are public APIs which allow to access an already dropped value +/// inside `ManuallyDrop`. +/// +/// # Pre-`1.96` Interaction with `Box` +/// +/// Before Rust `1.96.0`, if you had a `ManuallyDrop`, where the type `T` +/// was a `Box` or contained a `Box` inside, then dropping the `T` followed by +/// moving the `ManuallyDrop` was [considered to be undefined /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). -/// That is, the following code causes undefined behavior: +/// That is, the following code caused undefined behavior: /// /// ```no_run /// use std::mem::ManuallyDrop; @@ -58,31 +108,12 @@ use crate::ptr; /// unsafe { /// ManuallyDrop::drop(&mut x); /// } -/// let y = x; // Undefined behavior! +/// let y = x; // Undefined behavior! (pre 1.96.0) /// ``` /// -/// This is [likely to change in the -/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the -/// meantime, consider using [`MaybeUninit`] instead. -/// -/// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. -/// -/// Special care is needed when all of the conditions below are met: -/// * A struct or enum contains a `ManuallyDrop`. -/// * The `ManuallyDrop` is not inside a `union`. -/// * The struct or enum is part of public API, or is stored in a struct or an -/// enum that is part of public API. -/// * There is code that drops the contents of the `ManuallyDrop` field, and -/// this code is outside the struct or enum's `Drop` implementation. -/// -/// In particular, the following hazards may occur: -/// -/// #### Storing generic types -/// -/// If the `ManuallyDrop` contains a client-supplied generic type, the client -/// might provide a `Box` as that type. This would cause undefined behavior when -/// the struct or enum is later moved, as mentioned in the previous section. For -/// example, the following code causes undefined behavior: +/// Note that this could also have happen with a generic type where the user of +/// the library providing it could substitute the generic for a `Box<_>` and +/// then move the library type: /// /// ```no_run /// use std::mem::ManuallyDrop; @@ -101,7 +132,7 @@ use crate::ptr; /// self.is_some = false; /// unsafe { /// // SAFETY: `value` hasn't been dropped yet, as per the invariant -/// // (This is actually unsound!) +/// // (This is actually unsound pre rust 1.96.0!) /// ManuallyDrop::drop(&mut self.value); /// } /// } @@ -112,41 +143,7 @@ use crate::ptr; /// /// let mut option = BadOption::new(Box::new(42)); /// option.change_to_none(); -/// let option2 = option; // Undefined behavior! -/// ``` -/// -/// #### Deriving traits -/// -/// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on -/// the struct or enum could be unsound, since the derived implementations of -/// these traits would access the `ManuallyDrop` field. For example, the -/// following code causes undefined behavior: -/// -/// ```no_run -/// use std::mem::ManuallyDrop; -/// -/// // This derive is unsound in combination with the `ManuallyDrop::drop` call. -/// #[derive(Debug)] -/// pub struct Foo { -/// value: ManuallyDrop, -/// } -/// impl Foo { -/// pub fn new() -> Self { -/// let mut temp = Self { -/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) -/// }; -/// unsafe { -/// // SAFETY: `value` hasn't been dropped yet. -/// ManuallyDrop::drop(&mut temp.value); -/// } -/// temp -/// } -/// } -/// -/// // In another crate: -/// -/// let foo = Foo::new(); -/// println!("{:?}", foo); // Undefined behavior! +/// let option2 = option; // Undefined behavior! (pre 1.96) /// ``` /// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html diff --git a/src/doc/reference b/src/doc/reference index 01b0ee707f457..2c27905c15a51 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 01b0ee707f4571e803c8b2c471d8335a448f5d60 +Subproject commit 2c27905c15a51983b54d84f050d3bda096194d27 diff --git a/tests/codegen-llvm/c-variadic-lifetime.rs b/tests/codegen-llvm/c-variadic-lifetime.rs index 302bc621df497..794b98e03914c 100644 --- a/tests/codegen-llvm/c-variadic-lifetime.rs +++ b/tests/codegen-llvm/c-variadic-lifetime.rs @@ -16,6 +16,9 @@ unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { a + b + c - // CHECK: call void @llvm.va_end.p0(ptr nonnull %args) + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end + + // But we do still explicitly end the lifetime of the VaList. // CHECK: call void @llvm.lifetime.end.p0({{(i64 [0-9]+, )?}}ptr nonnull %args) } diff --git a/tests/codegen-llvm/c-variadic-va-end.rs b/tests/codegen-llvm/c-variadic-va-end.rs index b0d7371ba01c2..0be1c17257c66 100644 --- a/tests/codegen-llvm/c-variadic-va-end.rs +++ b/tests/codegen-llvm/c-variadic-va-end.rs @@ -11,9 +11,6 @@ unsafe extern "C" { pub unsafe extern "C" fn f(mut args: ...) { // CHECK: call void @llvm.va_start unsafe { g(&raw mut args as *mut u8) } - // We expect one call to the LLVM va_end from our desugaring of `...`. The `Drop` implementation - // should only call the rust va_end intrinsic, which is a no-op. - // - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. // CHECK-NOT: call void @llvm.va_end } diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs index 9a15342361cc5..741423efc36da 100644 --- a/tests/codegen-llvm/cffi/c-variadic-opt.rs +++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs @@ -16,5 +16,6 @@ extern "C" { pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { // CHECK: call void @llvm.va_start vprintf(fmt, ap) - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end } diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs index 0fa63b42c2de6..ceef7e72251d9 100644 --- a/tests/codegen-llvm/cffi/c-variadic.rs +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -31,7 +31,8 @@ pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { sum += ap.next_arg::(); } sum - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end } // Ensure that we generate the correct `call` signature when calling a Rust diff --git a/tests/ui/async-await/async-closures/auxiliary/block-on.rs b/tests/ui/async-await/async-closures/auxiliary/block-on.rs index 4ec45ddf33359..ed55f62378c71 100644 --- a/tests/ui/async-await/async-closures/auxiliary/block-on.rs +++ b/tests/ui/async-await/async-closures/auxiliary/block-on.rs @@ -1,5 +1,3 @@ -//@ edition: 2021 - use std::future::Future; use std::pin::pin; use std::task::*; diff --git a/tests/ui/async-await/async-closures/auxiliary/foreign.rs b/tests/ui/async-await/async-closures/auxiliary/foreign.rs index 935b029a7c5ad..f9c61e3d9cf86 100644 --- a/tests/ui/async-await/async-closures/auxiliary/foreign.rs +++ b/tests/ui/async-await/async-closures/auxiliary/foreign.rs @@ -1,4 +1,4 @@ -//@ edition:2021 +//@ edition: 2018 pub fn closure() -> impl AsyncFn() { async || { /* Don't really need to do anything here. */ } diff --git a/tests/ui/borrowck/borrowck-if-else-uninitialized.rs b/tests/ui/borrowck/borrowck-if-else-uninitialized.rs new file mode 100644 index 0000000000000..8ca1fc33ad948 --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-else-uninitialized.rs @@ -0,0 +1,12 @@ +fn foo(b: bool) { + let x; + if b { + x = 1; + } else { + println!("{x}"); //~ ERROR E0381 + } +} + +fn main() { + foo(true); +} diff --git a/tests/ui/borrowck/borrowck-if-else-uninitialized.stderr b/tests/ui/borrowck/borrowck-if-else-uninitialized.stderr new file mode 100644 index 0000000000000..543a3cfbe6807 --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-else-uninitialized.stderr @@ -0,0 +1,20 @@ +error[E0381]: used binding `x` isn't initialized on any path leading to this point + --> $DIR/borrowck-if-else-uninitialized.rs:6:20 + | +LL | let x; + | - binding declared here but left uninitialized +... +LL | } else { + | ------ if the `if` condition is `false` and this `else` arm is executed, `x` is not initialized +LL | println!("{x}"); + | ^ `x` used here but it isn't initialized on any path leading to this point + | + = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown +help: consider assigning a value + | +LL | let x = 42; + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.rs b/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.rs new file mode 100644 index 0000000000000..034e6495f5eed --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.rs @@ -0,0 +1,16 @@ +fn main() { + let internal_code: u32; + let is_admin = true; + let access_level = 2; + if is_admin { + if access_level == 1 { + internal_code = 101; + } else if access_level == 2 { + println!("Admin access pending for code: {internal_code}"); //~ ERROR E0381 + } else { + internal_code = 103; + } + } else { + internal_code = 404; + } +} diff --git a/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.stderr b/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.stderr new file mode 100644 index 0000000000000..947809d51e967 --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-elseif-else-uninitialezed.stderr @@ -0,0 +1,20 @@ +error[E0381]: used binding `internal_code` isn't initialized on any path leading to this point + --> $DIR/borrowck-if-elseif-else-uninitialezed.rs:9:55 + | +LL | let internal_code: u32; + | ------------- binding declared here but left uninitialized +... +LL | } else if access_level == 2 { + | ----------------- if this condition is `true`, `internal_code` is not initialized +LL | println!("Admin access pending for code: {internal_code}"); + | ^^^^^^^^^^^^^ `internal_code` used here but it isn't initialized on any path leading to this point + | + = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown +help: consider assigning a value + | +LL | let internal_code: u32 = 42; + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-match-multiple-uninitialized.rs b/tests/ui/borrowck/borrowck-match-multiple-uninitialized.rs new file mode 100644 index 0000000000000..4db2ea4a5e0fc --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-multiple-uninitialized.rs @@ -0,0 +1,20 @@ +enum Status { + Active, + Inactive, + Pending, +} +fn main() { + let message: &str; // Declared but not initialized + let current_status = Status::Pending; + match current_status { + Status::Active => { + message = "System is live."; + } + Status::Inactive => { + message = "System is down."; + } + Status::Pending => { + println!("{message}"); //~ ERROR E0381 + } + } +} diff --git a/tests/ui/borrowck/borrowck-match-multiple-uninitialized.stderr b/tests/ui/borrowck/borrowck-match-multiple-uninitialized.stderr new file mode 100644 index 0000000000000..21b02cdf55d8b --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-multiple-uninitialized.stderr @@ -0,0 +1,19 @@ +error[E0381]: used binding `message` isn't initialized on any path leading to this point + --> $DIR/borrowck-match-multiple-uninitialized.rs:17:24 + | +LL | let message: &str; // Declared but not initialized + | ------- binding declared here but left uninitialized +... +LL | Status::Pending => { + | --------------- if this pattern is matched, `message` is not initialized +LL | println!("{message}"); + | ^^^^^^^ `message` used here but it isn't initialized on any path leading to this point + | +help: consider assigning a value + | +LL | let message: &str = ""; // Declared but not initialized + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-match-uninitialized.rs b/tests/ui/borrowck/borrowck-match-uninitialized.rs new file mode 100644 index 0000000000000..e81f9b03df62c --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-uninitialized.rs @@ -0,0 +1,8 @@ +fn main() { + let x; + + match true { + true => x = 42, + false => println!("{x}") //~ ERROR E0381 + } +} diff --git a/tests/ui/borrowck/borrowck-match-uninitialized.stderr b/tests/ui/borrowck/borrowck-match-uninitialized.stderr new file mode 100644 index 0000000000000..5d15de3b2b52a --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-uninitialized.stderr @@ -0,0 +1,17 @@ +error[E0381]: used binding `x` isn't initialized on any path leading to this point + --> $DIR/borrowck-match-uninitialized.rs:6:29 + | +LL | let x; + | - binding declared here but left uninitialized +... +LL | false => println!("{x}") + | ^ `x` used here but it isn't initialized on any path leading to this point + | +help: consider assigning a value + | +LL | let x = 42; + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.rs b/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.rs new file mode 100644 index 0000000000000..18794eb99252e --- /dev/null +++ b/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.rs @@ -0,0 +1,7 @@ +// Regression test for https://github.com/rust-lang/rust/issues/157892 + +#![cfg_attr(a())] +//~^ ERROR malformed `cfg_attr` attribute input [E0539] +//~| ERROR malformed `cfg_attr` attribute input [E0539] + +fn main() {} diff --git a/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.stderr b/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.stderr new file mode 100644 index 0000000000000..3b97cd9607409 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg_attr-invalid-predicate-inner.stderr @@ -0,0 +1,34 @@ +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-invalid-predicate-inner.rs:3:1 + | +LL | #![cfg_attr(a())] + | ^^^^^^^^^^^^---^^ + | | + | valid arguments are `any`, `all`, `not` or `target` + | + = note: for more information, visit +help: must be of the form + | +LL - #![cfg_attr(a())] +LL + #![cfg_attr(predicate, attr1, attr2, ...)] + | + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-invalid-predicate-inner.rs:3:1 + | +LL | #![cfg_attr(a())] + | ^^^^^^^^^^^^---^^ + | | + | valid arguments are `any`, `all`, `not` or `target` + | + = note: for more information, visit + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: must be of the form + | +LL - #![cfg_attr(a())] +LL + #![cfg_attr(predicate, attr1, attr2, ...)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/const-generics/issues/issue-87493.stderr b/tests/ui/const-generics/issues/issue-87493.stderr index 42d32a0ee0502..8ab5289ac73b0 100644 --- a/tests/ui/const-generics/issues/issue-87493.stderr +++ b/tests/ui/const-generics/issues/issue-87493.stderr @@ -21,10 +21,6 @@ note: trait defined here, with 0 generic parameters | LL | pub trait MyTrait { | ^^^^^^^ -help: replace the generic bound with the associated type - | -LL | T: MyTrait, - | +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type-const-suggestion.rs b/tests/ui/const-generics/mgca/type-const-suggestion.rs new file mode 100644 index 0000000000000..8b01f17d41d9e --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-suggestion.rs @@ -0,0 +1,11 @@ +//! Regression test for . + +#![feature(min_generic_const_args)] + +trait Trait { + type const K: i32; +} +fn take(_: impl Trait<0>) {} +//~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied [E0107] + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type-const-suggestion.stderr b/tests/ui/const-generics/mgca/type-const-suggestion.stderr new file mode 100644 index 0000000000000..d59dc60ebca1c --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-suggestion.stderr @@ -0,0 +1,19 @@ +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/type-const-suggestion.rs:8:17 + | +LL | fn take(_: impl Trait<0>) {} + | ^^^^^ expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/type-const-suggestion.rs:5:7 + | +LL | trait Trait { + | ^^^^^ +help: turn the generic argument into an associated item binding + | +LL | fn take(_: impl Trait) {} + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/const-generics/mgca/type_const_in_pattern.rs b/tests/ui/const-generics/mgca/type_const_in_pattern.rs new file mode 100644 index 0000000000000..18062cd4cb1c7 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const_in_pattern.rs @@ -0,0 +1,33 @@ +//@ check-pass +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] +#![allow(irrefutable_let_patterns)] + +type const CONST: usize = 1_usize; + +struct Inherent; + +impl Inherent { + type const BAR: usize = 1_usize; +} + +trait Trait { + type const BAZ: usize; +} + +struct Assoc; + +impl Trait for Assoc { + type const BAZ: usize = 1_usize; +} + +fn main() { + if let CONST = 1 {} + if let Inherent::BAR = 1 {} + if let ::BAZ = 1 {} + + match CONST { + CONST => 0, + _ => 1, + }; +} diff --git a/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.rs b/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.rs new file mode 100644 index 0000000000000..31284298044d0 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + type const ASSOC: usize; +} + +fn test() { + if let ::ASSOC = 1 {} + //~^ ERROR could not evaluate constant pattern +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.stderr b/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.stderr new file mode 100644 index 0000000000000..419e03cfadc30 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const_in_pattern_too_generic.stderr @@ -0,0 +1,13 @@ +error: could not evaluate constant pattern + --> $DIR/type_const_in_pattern_too_generic.rs:9:12 + | +LL | trait Trait { + | ----------- +LL | type const ASSOC: usize; + | ----------------------- constant defined here +... +LL | if let ::ASSOC = 1 {} + | ^^^^^^^^^^^^^^^^^^^ could not evaluate constant + +error: aborting due to 1 previous error + diff --git a/tests/ui/error-codes/E0107.rs b/tests/ui/error-codes/E0107.rs index 161360a501285..f23c594ab80ba 100644 --- a/tests/ui/error-codes/E0107.rs +++ b/tests/ui/error-codes/E0107.rs @@ -54,7 +54,7 @@ pub trait T { fn trait_bound_generic>(_i: I) { //~^ ERROR trait takes 0 generic arguments - //~| HELP replace the generic bounds with the associated types + //~| HELP turn the generic arguments into associated item bindings } fn main() {} diff --git a/tests/ui/error-codes/E0107.stderr b/tests/ui/error-codes/E0107.stderr index 4aa83cf7f5ff4..21f741e41086c 100644 --- a/tests/ui/error-codes/E0107.stderr +++ b/tests/ui/error-codes/E0107.stderr @@ -139,7 +139,7 @@ note: trait defined here, with 0 generic parameters | LL | pub trait T { | ^ -help: replace the generic bounds with the associated types +help: turn the generic arguments into associated item bindings | LL | fn trait_bound_generic>(_i: I) { | +++ +++ diff --git a/tests/ui/lint/unused/auxiliary/unused-parens-bound-proc-macro.rs b/tests/ui/lint/unused/auxiliary/unused-parens-bound-proc-macro.rs new file mode 100644 index 0000000000000..7cb7e2112eba4 --- /dev/null +++ b/tests/ui/lint/unused/auxiliary/unused-parens-bound-proc-macro.rs @@ -0,0 +1,32 @@ +extern crate proc_macro; + +use proc_macro::{Group, Span, TokenStream, TokenTree}; + +// Recursively overwrite the span of every token (including group delimiters) +// with `span`. +fn respan(span: Span, stream: TokenStream) -> TokenStream { + stream + .into_iter() + .map(|tt| match tt { + TokenTree::Group(group) => { + let mut group = Group::new(group.delimiter(), respan(span, group.stream())); + group.set_span(span); + TokenTree::Group(group) + } + mut tt => { + tt.set_span(span); + tt + } + }) + .collect() +} + +/// Emits `const _: &dyn (Send) = &();` with every token carrying the span of the +/// macro's first input token. The parenthesized trait-object bound is therefore +/// reported at a span that does not actually contain parentheses in the source. +#[proc_macro] +pub fn emit_parenthesized_bound(input: TokenStream) -> TokenStream { + let span = input.into_iter().next().unwrap().span(); + let code: TokenStream = "const _: &dyn (Send) = &();".parse().unwrap(); + respan(span, code) +} diff --git a/tests/ui/lint/unused/unused-parens-trait-obj-proc-macro-144378.rs b/tests/ui/lint/unused/unused-parens-trait-obj-proc-macro-144378.rs new file mode 100644 index 0000000000000..58f4cd932a21f --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj-proc-macro-144378.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition: 2021 +//@ proc-macro: unused-parens-bound-proc-macro.rs + +// Regression test for #144378. +// +// A proc-macro can synthesize parentheses around a trait-object bound while +// reusing a span from its input. That span does not actually point at the +// parentheses, so the `unused_parens` lint must not blindly trim its first and +// last byte: doing so produced an invalid suggestion (e.g. turning a field +// `val: u8` into `al: u`) and, when the reused span started or ended on a +// multibyte character, ICEd by slicing through that character. + +#![deny(unused_parens)] +#![allow(uncommon_codepoints)] + +extern crate unused_parens_bound_proc_macro; + +// The generated `&dyn (Send)` reuses the span of the identifier `é`, whose +// first byte is the start of a two-byte character. Before the fix, trimming one +// byte off the front of that span sliced through `é` and ICEd; now the lint is +// skipped because the source span is not wrapped in parentheses. +unused_parens_bound_proc_macro::emit_parenthesized_bound!(é); + +fn main() {} diff --git a/tests/ui/scalable-vectors/layout.rs b/tests/ui/scalable-vectors/layout.rs new file mode 100644 index 0000000000000..1bc2972e2f5d0 --- /dev/null +++ b/tests/ui/scalable-vectors/layout.rs @@ -0,0 +1,28 @@ +//@ only-aarch64 +#![feature(rustc_attrs)] +#![crate_type = "lib"] + +// Tests that the computed layout size of scalable vectors is equal to +// `element size * element count * number of vectors`. Scalable vectors are of course scalable and +// so do not have a fixed size, but using this size with things like `llvm.memcpy` produces the +// correct and expected results. + +#[rustc_dump_layout(size)] +#[rustc_scalable_vector(4)] +struct ScalableFloat(f32); //~ ERROR: size: Size(16 bytes) + +#[rustc_dump_layout(size)] +#[rustc_scalable_vector(8)] +struct ScalableU8WithFewerCount(u8); //~ ERROR: size: Size(8 bytes) + +#[rustc_dump_layout(size)] +#[rustc_scalable_vector(16)] +struct ScalableU8(u8); //~ ERROR: size: Size(16 bytes) + +#[rustc_dump_layout(size)] +#[rustc_scalable_vector(16)] +struct ScalableBool(bool); //~ ERROR: size: Size(16 bytes) + +#[rustc_dump_layout(size)] +#[rustc_scalable_vector] +struct ScalableTuple(ScalableU8, ScalableU8, ScalableU8); //~ ERROR: size: Size(48 bytes) diff --git a/tests/ui/scalable-vectors/layout.stderr b/tests/ui/scalable-vectors/layout.stderr new file mode 100644 index 0000000000000..5867d8ee04b41 --- /dev/null +++ b/tests/ui/scalable-vectors/layout.stderr @@ -0,0 +1,32 @@ +error: size: Size(16 bytes) + --> $DIR/layout.rs:12:1 + | +LL | struct ScalableFloat(f32); + | ^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(8 bytes) + --> $DIR/layout.rs:16:1 + | +LL | struct ScalableU8WithFewerCount(u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(16 bytes) + --> $DIR/layout.rs:20:1 + | +LL | struct ScalableU8(u8); + | ^^^^^^^^^^^^^^^^^ + +error: size: Size(16 bytes) + --> $DIR/layout.rs:24:1 + | +LL | struct ScalableBool(bool); + | ^^^^^^^^^^^^^^^^^^^ + +error: size: Size(48 bytes) + --> $DIR/layout.rs:28:1 + | +LL | struct ScalableTuple(ScalableU8, ScalableU8, ScalableU8); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs index c2387bf5411d1..a97b1491857f5 100644 --- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs +++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs @@ -4,9 +4,11 @@ pub trait T { type C; } pub struct Foo { - i: Box>, + i: Box>, //~^ ERROR trait takes 2 generic arguments but 4 generic arguments were supplied } +fn take(_: impl Iterator<0>) {} +//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied fn main() {} diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 18cf0674f0231..8f49eb55d11e1 100644 --- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -1,7 +1,7 @@ error[E0107]: trait takes 2 generic arguments but 4 generic arguments were supplied --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16 | -LL | i: Box>, +LL | i: Box>, | ^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `X`, `Y` @@ -9,11 +9,17 @@ note: trait defined here, with 2 generic parameters: `X`, `Y` | LL | pub trait T { | ^ - - -help: replace the generic bounds with the associated types +help: turn the generic arguments into associated item bindings | -LL | i: Box>, +LL | i: Box>, | +++ +++ -error: aborting due to 1 previous error +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/use-type-argument-instead-of-assoc-type.rs:11:17 + | +LL | fn take(_: impl Iterator<0>) {} + | ^^^^^^^^ expected 0 generic arguments + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index 54c0cf8ebee91..0c045660cf7c2 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -27,7 +27,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), i32> { | +++++++ @@ -43,7 +43,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ @@ -59,7 +59,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | struct Struct> { | +++++++ @@ -75,7 +75,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | trait AnotherTrait> {} | +++++++ @@ -91,7 +91,7 @@ note: trait defined here, with 1 generic parameter: `T` | LL | pub trait Trait { | ^^^^^ - -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | impl> Struct {} | +++++++ @@ -122,7 +122,7 @@ note: trait defined here, with 1 generic parameter: `T` LL | pub trait Trait { | ^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ diff --git a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr index acda3418894d6..e02bb32c13c0c 100644 --- a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr +++ b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr @@ -9,7 +9,7 @@ note: trait defined here, with 0 generic parameters | LL | trait Output<'a> { | ^^^^^^ -help: replace the generic bound with the associated type +help: turn the generic argument into an associated item binding | LL | F: for<'a> FnOnce(>::Type), | ++++++