diff --git a/RELEASES.md b/RELEASES.md index 29c787f4e14c6..f180d740a3d17 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,118 @@ +Version 1.94.0 (2026-03-05) +========================== + + + +Language +-------- +- [Impls and impl items inherit `dead_code` lint level of the corresponding traits and trait items](https://github.com/rust-lang/rust/pull/144113) +- [Stabilize additional 29 RISC-V target features including large portions of the RVA22U64 / RVA23U64 profiles](https://github.com/rust-lang/rust/pull/145948) +- [Add warn-by-default `unused_visibilities` lint for visibility on `const _` declarations](https://github.com/rust-lang/rust/pull/147136) +- [Update to Unicode 17](https://github.com/rust-lang/rust/pull/148321) +- [Avoid incorrect lifetime errors for closures](https://github.com/rust-lang/rust/pull/148329) + + + +Platform Support +---------------- + +- [Add `riscv64im-unknown-none-elf` as a tier 3 target](https://github.com/rust-lang/rust/pull/148790) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html + + + +Libraries +--------- + +- [Relax `T: Ord` bound for some `BinaryHeap` methods.](https://github.com/rust-lang/rust/pull/149408) + + + +Stabilized APIs +--------------- + +- [`<[T]>::array_windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.array_windows) +- [`<[T]>::element_offset`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.element_offset) +- [`LazyCell::get`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.get) +- [`LazyCell::get_mut`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.get_mut) +- [`LazyCell::force_mut`](https://doc.rust-lang.org/stable/std/cell/struct.LazyCell.html#method.force_mut) +- [`LazyLock::get`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.get) +- [`LazyLock::get_mut`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.get_mut) +- [`LazyLock::force_mut`](https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html#method.force_mut) +- [`impl TryFrom for usize`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html#impl-TryFrom%3Cchar%3E-for-usize) +- [`std::iter::Peekable::next_if_map`](https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_map) +- [`std::iter::Peekable::next_if_map_mut`](https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_map_mut) +- [x86 `avx512fp16` intrinsics](https://github.com/rust-lang/rust/issues/127213) + (excluding those that depend directly on the unstable `f16` type) +- [AArch64 NEON fp16 intrinsics](https://github.com/rust-lang/rust/issues/136306) + (excluding those that depend directly on the unstable `f16` type) +- [`f32::consts::EULER_GAMMA`](https://doc.rust-lang.org/stable/std/f32/consts/constant.EULER_GAMMA.html) +- [`f64::consts::EULER_GAMMA`](https://doc.rust-lang.org/stable/std/f64/consts/constant.EULER_GAMMA.html) +- [`f32::consts::GOLDEN_RATIO`](https://doc.rust-lang.org/stable/std/f32/consts/constant.GOLDEN_RATIO.html) +- [`f64::consts::GOLDEN_RATIO`](https://doc.rust-lang.org/stable/std/f64/consts/constant.GOLDEN_RATIO.html) + + +These previously stable APIs are now stable in const contexts: + +- [`f32::mul_add`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.mul_add) +- [`f64::mul_add`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.mul_add) + + + + +Cargo +----- + +- Stabilize the config include key. The top-level include config key allows loading additional config files, enabling better organization, sharing, and management of Cargo configurations across projects and environments. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#including-extra-configuration-files) [#16284](https://github.com/rust-lang/cargo/pull/16284) +- Stabilize the pubtime field in registry index. This records when a crate version was published and enables time-based dependency resolution in the future. Note that crates.io will gradually backfill existing packages when a new version is published. Not all crates have pubtime yet. [#16369](https://github.com/rust-lang/cargo/pull/16369) [#16372](https://github.com/rust-lang/cargo/pull/16372) +- Cargo now parses [TOML v1.1](https://toml.io/en/v1.1.0) for manifests and configuration files. Note that using these features in Cargo.toml will raise your development MSRV, but the published manifest remains compatible with older parsers. [#16415](https://github.com/rust-lang/cargo/pull/16415) +- [Make `CARGO_BIN_EXE_` available at runtime ](https://github.com/rust-lang/cargo/pull/16421/) + + + +Compatibility Notes +------------------- +- [Forbid freely casting lifetime bounds of `dyn`-types](https://github.com/rust-lang/rust/pull/136776) +- [Make closure capturing have consistent and correct behaviour around patterns](https://github.com/rust-lang/rust/pull/138961) + Some finer details of how precise closure captures get affected by pattern matching have been changed. In some cases, this can cause a non-move closure that was previously capturing an entire variable by move, to now capture only part of that variable by move, and other parts by borrow. This can cause the borrow checker to complain where it previously didn't, or cause `Drop` to run at a different point in time. +- [Standard library macros are now imported via prelude, not via injected `#[macro_use]`](https://github.com/rust-lang/rust/pull/139493) + This will raise an error if macros of the same name are glob imported. + For example if a crate defines their own `matches` macro and then glob imports that, + it's now ambiguous whether the custom or standard library `matches` is meant and + an explicit import of the name is required to resolve the ambiguity. + One exception is `core::panic` and `std::panic`, if their import is ambiguous + a new warning ([`ambiguous_panic_imports`](https://github.com/rust-lang/rust/issues/147319)) is raised. + This may raise a new warning ([`ambiguous_panic_imports`](https://github.com/rust-lang/rust/issues/147319)) on `#![no_std]` code glob importing the std crate. + Both `core::panic!` and `std::panic!` are then in scope and which is used is ambiguous. +- [Don't strip shebang in expression-context `include!(…)`s](https://github.com/rust-lang/rust/pull/146377) + This can cause previously working includes to no longer compile if they included files which started with a shebang. +- [Ambiguous glob reexports are now also visible cross-crate](https://github.com/rust-lang/rust/pull/147984) + This unifies behavior between local and cross-crate errors on these exports, which may introduce new ambiguity errors. +- [Don't normalize where-clauses before checking well-formedness](https://github.com/rust-lang/rust/pull/148477) +- [Introduce a future compatibility warning on codegen attributes on body-free trait methods](https://github.com/rust-lang/rust/pull/148756) + These attributes currently have no effect in this position. +- [On Windows `std::time::SystemTime::checked_sub_duration` will return `None` for times before the Windows epoch (1/1/1601)](https://github.com/rust-lang/rust/pull/148825) +- [Lifetime identifiers such as `'a` are now NFC normalized](https://github.com/rust-lang/rust/pull/149192). +- [Overhaul filename handling for cross-compiler consistency](https://github.com/rust-lang/rust/pull/149709) + Any paths emitted by compiler now always respect the relative-ness of the paths and `--remap-path-prefix` given originally. + One side-effect of this change is that paths emitted for local crates in Cargo (path dependencies and workspace members) are no longer absolute but relative when emitted as part of a diagnostic in a downstream crate. + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Switch to `annotate-snippets` for error emission](https://github.com/rust-lang/rust/pull/150032) + This should preserve mostly the same outputs in rustc error messages. + Version 1.93.1 (2026-02-12) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 04bad6142b6cc..333cfce47abe2 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1724,6 +1724,12 @@ pub enum StructRest { Rest(Span), /// No trailing `..` or expression. None, + /// No trailing `..` or expression, and also, a parse error occurred inside the struct braces. + /// + /// This struct should be treated similarly to as if it had an `..` in it, + /// in particular rather than reporting missing fields, because the parse error + /// makes which fields the struct was intended to have not fully known. + NoneWithError(ErrorGuaranteed), } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5b31c421bf346..4a2992038003c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -340,12 +340,13 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), ), ExprKind::Struct(se) => { - let rest = match &se.rest { - StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)), + let rest = match se.rest { + StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)), StructRest::Rest(sp) => { - hir::StructTailExpr::DefaultFields(self.lower_span(*sp)) + hir::StructTailExpr::DefaultFields(self.lower_span(sp)) } StructRest::None => hir::StructTailExpr::None, + StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar), }; hir::ExprKind::Struct( self.arena.alloc(self.lower_qpath( @@ -1435,7 +1436,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(self.lower_span(e.span)) } StructRest::Rest(span) => Some(self.lower_span(*span)), - StructRest::None => None, + StructRest::None | StructRest::NoneWithError(_) => None, }; let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted); return self.pat_without_dbm(lhs.span, struct_pat); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 7dce7f6d41954..9b4ff2b63bd45 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -162,7 +162,7 @@ impl<'a> State<'a> { self.word("{"); let has_rest = match rest { ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true, - ast::StructRest::None => false, + ast::StructRest::None | ast::StructRest::NoneWithError(_) => false, }; if fields.is_empty() && !has_rest { self.word("}"); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 460f4afea963f..9e6b366464341 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -8,7 +8,7 @@ use rustc_codegen_ssa::traits::{ use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_target::spec::{Abi, Arch, Env}; +use rustc_target::spec::{Arch, Env, RustcAbi}; use crate::builder::Builder; use crate::llvm::{Type, Value}; @@ -272,7 +272,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( // Rust does not currently support any powerpc softfloat targets. let target = &bx.cx.tcx.sess.target; - let is_soft_float_abi = target.abi == Abi::SoftFloat; + let is_soft_float_abi = target.rustc_abi == Some(RustcAbi::Softfloat); assert!(!is_soft_float_abi); // All instances of VaArgSafe are passed directly. @@ -1077,7 +1077,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::Yes, ), - Arch::RiscV32 if target.abi == Abi::Ilp32e => { + Arch::RiscV32 if target.llvm_abiname == "ilp32e" => { // FIXME: clang manually adjusts the alignment for this ABI. It notes: // // > To be compatible with GCC's behaviors, we force arguments with diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index de00cbc8e7098..326eb2cd13384 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2658,7 +2658,9 @@ impl Expr<'_> { ExprKind::Struct(_, fields, init) => { let init_side_effects = match init { StructTailExpr::Base(init) => init.can_have_side_effects(), - StructTailExpr::DefaultFields(_) | StructTailExpr::None => false, + StructTailExpr::DefaultFields(_) + | StructTailExpr::None + | StructTailExpr::NoneWithError(_) => false, }; fields.iter().map(|field| field.expr).any(|e| e.can_have_side_effects()) || init_side_effects @@ -2950,6 +2952,12 @@ pub enum StructTailExpr<'hir> { /// fields' default values will be used to populate any fields not explicitly mentioned: /// `Foo { .. }`. DefaultFields(Span), + /// No trailing `..` was written, and also, a parse error occurred inside the struct braces. + /// + /// This struct should be treated similarly to as if it had an `..` in it, + /// in particular rather than reporting missing fields, because the parse error + /// makes which fields the struct was intended to have not fully known. + NoneWithError(ErrorGuaranteed), } /// Represents an optionally `Self`-qualified value/type path or associated extension. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6a69326d8c847..25ef56f8b0f2c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -830,7 +830,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr_field, fields); match optional_base { StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)), - StructTailExpr::None | StructTailExpr::DefaultFields(_) => {} + StructTailExpr::None + | StructTailExpr::NoneWithError(_) + | StructTailExpr::DefaultFields(_) => {} } } ExprKind::Tup(subexpressions) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ec0688b64f3dd..369c7c077474a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1314,6 +1314,7 @@ impl<'a> State<'a> { self.end(ib); } hir::StructTailExpr::None => {} + hir::StructTailExpr::NoneWithError(_) => {} } self.space(); self.word("}"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fd83f6f9ae1eb..9f2134e050bc0 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2000,229 +2000,256 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - if let hir::StructTailExpr::DefaultFields(span) = *base_expr { - let mut missing_mandatory_fields = Vec::new(); - let mut missing_optional_fields = Vec::new(); - for f in &variant.fields { - let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); - if let Some(_) = remaining_fields.remove(&ident) { - if f.value.is_none() { - missing_mandatory_fields.push(ident); - } else { - missing_optional_fields.push(ident); + match *base_expr { + hir::StructTailExpr::DefaultFields(span) => { + let mut missing_mandatory_fields = Vec::new(); + let mut missing_optional_fields = Vec::new(); + for f in &variant.fields { + let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + if f.value.is_none() { + missing_mandatory_fields.push(ident); + } else { + missing_optional_fields.push(ident); + } } } - } - if !self.tcx.features().default_field_values() { - let sugg = self.tcx.crate_level_attribute_injection_span(); - self.dcx().emit_err(BaseExpressionDoubleDot { - span: span.shrink_to_hi(), - // We only mention enabling the feature if this is a nightly rustc *and* the - // expression would make sense with the feature enabled. - default_field_values_suggestion: if self.tcx.sess.is_nightly_build() - && missing_mandatory_fields.is_empty() - && !missing_optional_fields.is_empty() - { - Some(sugg) - } else { - None - }, - add_expr: if !missing_mandatory_fields.is_empty() - || !missing_optional_fields.is_empty() - { - Some(BaseExpressionDoubleDotAddExpr { span: span.shrink_to_hi() }) - } else { - None - }, - remove_dots: if missing_mandatory_fields.is_empty() - && missing_optional_fields.is_empty() - { - Some(BaseExpressionDoubleDotRemove { span }) - } else { - None - }, - }); - return; - } - if variant.fields.is_empty() { - let mut err = self.dcx().struct_span_err( - span, - format!( - "`{adt_ty}` has no fields, `..` needs at least one default field in the \ - struct definition", - ), - ); - err.span_label(path_span, "this type has no fields"); - err.emit(); - } - if !missing_mandatory_fields.is_empty() { - let s = pluralize!(missing_mandatory_fields.len()); - let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); - self.dcx() - .struct_span_err( - span.shrink_to_lo(), - format!("missing field{s} {fields} in initializer"), - ) - .with_span_label( - span.shrink_to_lo(), - "fields that do not have a defaulted value must be provided explicitly", - ) - .emit(); - return; - } - let fru_tys = match adt_ty.kind() { - ty::Adt(adt, args) if adt.is_struct() => variant - .fields - .iter() - .map(|f| self.normalize(span, f.ty(self.tcx, args))) - .collect(), - ty::Adt(adt, args) if adt.is_enum() => variant - .fields - .iter() - .map(|f| self.normalize(span, f.ty(self.tcx, args))) - .collect(), - _ => { - self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { span }); + if !self.tcx.features().default_field_values() { + let sugg = self.tcx.crate_level_attribute_injection_span(); + self.dcx().emit_err(BaseExpressionDoubleDot { + span: span.shrink_to_hi(), + // We only mention enabling the feature if this is a nightly rustc *and* the + // expression would make sense with the feature enabled. + default_field_values_suggestion: if self.tcx.sess.is_nightly_build() + && missing_mandatory_fields.is_empty() + && !missing_optional_fields.is_empty() + { + Some(sugg) + } else { + None + }, + add_expr: if !missing_mandatory_fields.is_empty() + || !missing_optional_fields.is_empty() + { + Some(BaseExpressionDoubleDotAddExpr { span: span.shrink_to_hi() }) + } else { + None + }, + remove_dots: if missing_mandatory_fields.is_empty() + && missing_optional_fields.is_empty() + { + Some(BaseExpressionDoubleDotRemove { span }) + } else { + None + }, + }); return; } - }; - self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); - } else if let hir::StructTailExpr::Base(base_expr) = base_expr { - // FIXME: We are currently creating two branches here in order to maintain - // consistency. But they should be merged as much as possible. - let fru_tys = if self.tcx.features().type_changing_struct_update() { - if adt.is_struct() { - // Make some fresh generic parameters for our ADT type. - let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); - // We do subtyping on the FRU fields first, so we can - // learn exactly what types we expect the base expr - // needs constrained to be compatible with the struct - // type we expect from the expectation value. - let fru_tys = variant - .fields - .iter() - .map(|f| { - let fru_ty = self - .normalize(expr.span, self.field_ty(base_expr.span, f, fresh_args)); - let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); - if let Some(_) = remaining_fields.remove(&ident) { - let target_ty = self.field_ty(base_expr.span, f, args); - let cause = self.misc(base_expr.span); - match self.at(&cause, self.param_env).sup( - // We're already using inference variables for any params, and don't allow converting - // between different structs, so there is no way this ever actually defines an opaque type. - // Thus choosing `Yes` is fine. - DefineOpaqueTypes::Yes, - target_ty, - fru_ty, - ) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations) - } - Err(_) => { - span_bug!( - cause.span, - "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}", - variant.name, - ident.name, - ); - } - } - } - self.resolve_vars_if_possible(fru_ty) - }) - .collect(); - // The use of fresh args that we have subtyped against - // our base ADT type's fields allows us to guide inference - // along so that, e.g. - // ``` - // MyStruct<'a, F1, F2, const C: usize> { - // f: F1, - // // Other fields that reference `'a`, `F2`, and `C` - // } - // - // let x = MyStruct { - // f: 1usize, - // ..other_struct - // }; - // ``` - // will have the `other_struct` expression constrained to - // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... - // This is important to allow coercions to happen in - // `other_struct` itself. See `coerce-in-base-expr.rs`. - let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_args); - self.check_expr_has_type_or_error( - base_expr, - self.resolve_vars_if_possible(fresh_base_ty), - |_| {}, + if variant.fields.is_empty() { + let mut err = self.dcx().struct_span_err( + span, + format!( + "`{adt_ty}` has no fields, `..` needs at least one default field in \ + the struct definition", + ), ); - fru_tys - } else { - // Check the base_expr, regardless of a bad expected adt_ty, so we can get - // type errors on that expression, too. - self.check_expr(base_expr); - self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); - return; + err.span_label(path_span, "this type has no fields"); + err.emit(); } - } else { - self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { - let base_ty = self.typeck_results.borrow().expr_ty(*base_expr); - let same_adt = matches!((adt_ty.kind(), base_ty.kind()), - (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt); - if self.tcx.sess.is_nightly_build() && same_adt { - feature_err( - &self.tcx.sess, - sym::type_changing_struct_update, - base_expr.span, - "type changing struct updating is experimental", + if !missing_mandatory_fields.is_empty() { + let s = pluralize!(missing_mandatory_fields.len()); + let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); + self.dcx() + .struct_span_err( + span.shrink_to_lo(), + format!("missing field{s} {fields} in initializer"), + ) + .with_span_label( + span.shrink_to_lo(), + "fields that do not have a defaulted value must be provided explicitly", ) .emit(); - } - }); - match adt_ty.kind() { + return; + } + let fru_tys = match adt_ty.kind() { ty::Adt(adt, args) if adt.is_struct() => variant .fields .iter() - .map(|f| self.normalize(expr.span, f.ty(self.tcx, args))) + .map(|f| self.normalize(span, f.ty(self.tcx, args))) + .collect(), + ty::Adt(adt, args) if adt.is_enum() => variant + .fields + .iter() + .map(|f| self.normalize(span, f.ty(self.tcx, args))) .collect(), _ => { + self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { span }); + return; + } + }; + self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); + } + hir::StructTailExpr::Base(base_expr) => { + // FIXME: We are currently creating two branches here in order to maintain + // consistency. But they should be merged as much as possible. + let fru_tys = if self.tcx.features().type_changing_struct_update() { + if adt.is_struct() { + // Make some fresh generic parameters for our ADT type. + let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); + // We do subtyping on the FRU fields first, so we can + // learn exactly what types we expect the base expr + // needs constrained to be compatible with the struct + // type we expect from the expectation value. + let fru_tys = variant + .fields + .iter() + .map(|f| { + let fru_ty = self.normalize( + expr.span, + self.field_ty(base_expr.span, f, fresh_args), + ); + let ident = + self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + let target_ty = self.field_ty(base_expr.span, f, args); + let cause = self.misc(base_expr.span); + match self.at(&cause, self.param_env).sup( + // We're already using inference variables for any params, + // and don't allow converting between different structs, + // so there is no way this ever actually defines an opaque + // type. Thus choosing `Yes` is fine. + DefineOpaqueTypes::Yes, + target_ty, + fru_ty, + ) { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations) + } + Err(_) => { + span_bug!( + cause.span, + "subtyping remaining fields of type changing FRU \ + failed: {target_ty} != {fru_ty}: {}::{}", + variant.name, + ident.name, + ); + } + } + } + self.resolve_vars_if_possible(fru_ty) + }) + .collect(); + // The use of fresh args that we have subtyped against + // our base ADT type's fields allows us to guide inference + // along so that, e.g. + // ``` + // MyStruct<'a, F1, F2, const C: usize> { + // f: F1, + // // Other fields that reference `'a`, `F2`, and `C` + // } + // + // let x = MyStruct { + // f: 1usize, + // ..other_struct + // }; + // ``` + // will have the `other_struct` expression constrained to + // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... + // This is important to allow coercions to happen in + // `other_struct` itself. See `coerce-in-base-expr.rs`. + let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_args); + self.check_expr_has_type_or_error( + base_expr, + self.resolve_vars_if_possible(fresh_base_ty), + |_| {}, + ); + fru_tys + } else { + // Check the base_expr, regardless of a bad expected adt_ty, so we can get + // type errors on that expression, too. + self.check_expr(base_expr); self.dcx() .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); return; } + } else { + self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { + let base_ty = self.typeck_results.borrow().expr_ty(base_expr); + let same_adt = matches!((adt_ty.kind(), base_ty.kind()), + (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt); + if self.tcx.sess.is_nightly_build() && same_adt { + feature_err( + &self.tcx.sess, + sym::type_changing_struct_update, + base_expr.span, + "type changing struct updating is experimental", + ) + .emit(); + } + }); + match adt_ty.kind() { + ty::Adt(adt, args) if adt.is_struct() => variant + .fields + .iter() + .map(|f| self.normalize(expr.span, f.ty(self.tcx, args))) + .collect(), + _ => { + self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { + span: base_expr.span, + }); + return; + } + } + }; + self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); + } + rustc_hir::StructTailExpr::NoneWithError(ErrorGuaranteed { .. }) => { + // If parsing the struct recovered from a syntax error, do not report missing + // fields. This prevents spurious errors when a field is intended to be present + // but a preceding syntax error caused it not to be parsed. For example, if a + // struct type `StructName` has fields `foo` and `bar`, then + // StructName { foo(), bar: 2 } + // will not successfully parse a field `foo`, but we will not mention that, + // since the syntax error has already been reported. + } + rustc_hir::StructTailExpr::None => { + if adt_kind != AdtKind::Union + && !remaining_fields.is_empty() + //~ non_exhaustive already reported, which will only happen for extern modules + && !variant.field_list_has_applicable_non_exhaustive() + { + debug!(?remaining_fields); + + // Report missing fields. + + let private_fields: Vec<&ty::FieldDef> = variant + .fields + .iter() + .filter(|field| { + !field.vis.is_accessible_from(tcx.parent_module(expr.hir_id), tcx) + }) + .collect(); + + if !private_fields.is_empty() { + self.report_private_fields( + adt_ty, + path_span, + expr.span, + private_fields, + hir_fields, + ); + } else { + self.report_missing_fields( + adt_ty, + path_span, + expr.span, + remaining_fields, + variant, + hir_fields, + args, + ); + } } - }; - self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); - } else if adt_kind != AdtKind::Union - && !remaining_fields.is_empty() - //~ non_exhaustive already reported, which will only happen for extern modules - && !variant.field_list_has_applicable_non_exhaustive() - { - debug!(?remaining_fields); - let private_fields: Vec<&ty::FieldDef> = variant - .fields - .iter() - .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr.hir_id), tcx)) - .collect(); - - if !private_fields.is_empty() { - self.report_private_fields( - adt_ty, - path_span, - expr.span, - private_fields, - hir_fields, - ); - } else { - self.report_missing_fields( - adt_ty, - path_span, - expr.span, - remaining_fields, - variant, - hir_fields, - args, - ); } } } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 94f682a8859e9..0a492c795b29c 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -673,7 +673,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let with_expr = match *opt_with { hir::StructTailExpr::Base(w) => &*w, - hir::StructTailExpr::DefaultFields(_) | hir::StructTailExpr::None => { + hir::StructTailExpr::DefaultFields(_) + | hir::StructTailExpr::None + | hir::StructTailExpr::NoneWithError(_) => { return Ok(()); } }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b63feb022ff0c..8e6e9af5a4867 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -632,7 +632,8 @@ impl<'tcx> ThirBuildCx<'tcx> { .collect(), ) } - hir::StructTailExpr::None => AdtExprBase::None, + hir::StructTailExpr::None + | hir::StructTailExpr::NoneWithError(_) => AdtExprBase::None, }, })) } @@ -669,7 +670,10 @@ impl<'tcx> ThirBuildCx<'tcx> { hir::StructTailExpr::Base(base) => { span_bug!(base.span, "unexpected res: {:?}", res); } - hir::StructTailExpr::None => AdtExprBase::None, + hir::StructTailExpr::None + | hir::StructTailExpr::NoneWithError(_) => { + AdtExprBase::None + } }, })) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1a4c5238f72bc..e6f73e41f0821 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3842,6 +3842,15 @@ impl<'a> Parser<'a> { recovered_async = Some(guar); } + // If we encountered an error which we are recovering from, treat the struct + // as if it has a `..` in it, because we don’t know what fields the user + // might have *intended* it to have. + // + // This assignment will be overwritten if we actually parse a `..` later. + // + // (Note that this code is duplicated between here and below in comma parsing. + base = ast::StructRest::NoneWithError(guar); + // If the next token is a comma, then try to parse // what comes next as additional fields, rather than // bailing out until next `}`. @@ -3892,6 +3901,10 @@ impl<'a> Parser<'a> { } else if let Some(f) = field_ident(self, guar) { fields.push(f); } + + // See comment above on this same assignment inside of field parsing. + base = ast::StructRest::NoneWithError(guar); + self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); let _ = self.eat(exp!(Comma)); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 287e8579e080a..63860dfdd1a65 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1100,7 +1100,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { qpath.span(), ); } - hir::StructTailExpr::None => { + hir::StructTailExpr::None | hir::StructTailExpr::NoneWithError(_) => { let mut failed_fields = vec![]; for field in fields { let (hir_id, use_ctxt) = (field.hir_id, field.ident.span); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3e9476b124f67..6e9d4a38d987c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -5066,7 +5066,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { match &se.rest { StructRest::Base(expr) => self.visit_expr(expr), StructRest::Rest(_span) => {} - StructRest::None => {} + StructRest::None | StructRest::NoneWithError(_) => {} } } diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 13be3888611f1..e9a19aa7024bb 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -3,7 +3,7 @@ use std::iter; use rustc_abi::{BackendRepr, HasDataLayout, Primitive, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; -use crate::spec::{Abi, HasTargetSpec, Target}; +use crate::spec::{HasTargetSpec, RustcAbi, Target}; /// Indicates the variant of the AArch64 ABI we are compiling for. /// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI. @@ -34,7 +34,7 @@ where RegKind::Integer => false, // The softfloat ABI treats floats like integers, so they // do not get homogeneous aggregate treatment. - RegKind::Float => cx.target_spec().abi != Abi::SoftFloat, + RegKind::Float => cx.target_spec().rustc_abi != Some(RustcAbi::Softfloat), RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; @@ -43,7 +43,7 @@ where } fn softfloat_float_abi(target: &Target, arg: &mut ArgAbi<'_, Ty>) { - if target.abi != Abi::SoftFloat { + if target.rustc_abi != Some(RustcAbi::Softfloat) { return; } // Do *not* use the float registers for passing arguments, as that would make LLVM pick the ABI diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d9c872c9b4352..a4460a3725174 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2210,8 +2210,10 @@ pub struct TargetOptions { pub env: Env, /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"` /// or `"eabihf"`. Defaults to [`Abi::Unspecified`]. - /// This field is *not* forwarded directly to LLVM; its primary purpose is `cfg(target_abi)`. - /// However, parts of the backend do check this field for specific values to enable special behavior. + /// This field is *not* forwarded directly to LLVM and therefore does not control which ABI (in + /// the sense of function calling convention) is actually used; its primary purpose is + /// `cfg(target_abi)`. The actual calling convention is controlled by `llvm_abiname`, + /// `llvm_floatabi`, and `rustc_abi`. pub abi: Abi, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". #[rustc_lint_opt_deny_field_access( @@ -3228,8 +3230,8 @@ impl Target { ), RustcAbi::Softfloat => check_matches!( self.arch, - Arch::X86 | Arch::X86_64 | Arch::S390x, - "`softfloat` ABI is only valid for x86 and s390x targets" + Arch::X86 | Arch::X86_64 | Arch::S390x | Arch::AArch64, + "`softfloat` ABI is only valid for x86, s390x, and aarch64 targets" ), } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs index 07512c01dc4a8..e204c6466e297 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs @@ -8,13 +8,14 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, - Target, TargetMetadata, TargetOptions, + Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { abi: Abi::SoftFloat, + rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), features: "+v8a,+strict-align,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index ad444c139bff6..ed2e2fb6ab70b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -7,13 +7,14 @@ // For example, `-C target-cpu=cortex-a53`. use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, - Target, TargetMetadata, TargetOptions, + Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { abi: Abi::SoftFloat, + rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), features: "+v8a,+strict-align,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs index 63f518873c609..6f11f97e3d1df 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs @@ -1,11 +1,12 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, - Target, TargetMetadata, TargetOptions, + Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { abi: Abi::SoftFloat, + rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c3de7e257662f..80674ab4cf8a2 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_macros::HashStable_Generic; use rustc_span::{Symbol, sym}; -use crate::spec::{Abi, Arch, FloatAbi, RustcAbi, Target}; +use crate::spec::{Arch, FloatAbi, RustcAbi, Target}; /// Features that control behaviour of rustc, rather than the codegen. /// These exist globally and are not in the target-specific lists below. @@ -1154,17 +1154,21 @@ impl Target { Arch::AArch64 | Arch::Arm64EC => { // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force // the use of soft-float, so all we can do here is some crude hacks. - if self.abi == Abi::SoftFloat { - // LLVM will use float registers when `fp-armv8` is available, e.g. for - // calls to built-ins. The only way to ensure a consistent softfloat ABI - // on aarch64 is to never enable `fp-armv8`, so we enforce that. - // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the - // feature we have to mark as incompatible. - FeatureConstraints { required: &[], incompatible: &["neon"] } - } else { - // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. - // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up. - FeatureConstraints { required: &["neon"], incompatible: &[] } + match self.rustc_abi { + Some(RustcAbi::Softfloat) => { + // LLVM will use float registers when `fp-armv8` is available, e.g. for + // calls to built-ins. The only way to ensure a consistent softfloat ABI + // on aarch64 is to never enable `fp-armv8`, so we enforce that. + // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the + // feature we have to mark as incompatible. + FeatureConstraints { required: &[], incompatible: &["neon"] } + } + None => { + // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. + // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up. + FeatureConstraints { required: &["neon"], incompatible: &[] } + } + Some(r) => panic!("invalid Rust ABI for aarch64: {r:?}"), } } Arch::RiscV32 | Arch::RiscV64 => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 386c75dad9dd3..814333859488f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3883,7 +3883,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.span_note(assoc_span, msg); } ObligationCauseCode::TrivialBound => { - err.help("see issue #48214"); tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]); } ObligationCauseCode::OpaqueReturnType(expr_info) => { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9e081e65f9ad6..2e82f45771823 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -631,8 +631,15 @@ pub const trait Iterator { Zip::new(self, other.into_iter()) } - /// Creates a new iterator which places a copy of `separator` between adjacent - /// items of the original iterator. + /// Creates a new iterator which places a copy of `separator` between items + /// of the original iterator. + /// + /// Specifically on fused iterators, it is guaranteed that the new iterator + /// places a copy of `separator` between adjacent `Some(_)` items. However, + /// for non-fused iterators, [`intersperse`] will create a new iterator that + /// is a fused version of the original iterator and place a copy of `separator` + /// between adjacent `Some(_)` items. This behavior for non-fused iterators + /// is subject to change. /// /// In case `separator` does not implement [`Clone`] or needs to be /// computed every time, use [`intersperse_with`]. @@ -663,6 +670,7 @@ pub const trait Iterator { /// ``` /// /// [`Clone`]: crate::clone::Clone + /// [`intersperse`]: Iterator::intersperse /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", issue = "79524")] @@ -676,12 +684,19 @@ pub const trait Iterator { } /// Creates a new iterator which places an item generated by `separator` - /// between adjacent items of the original iterator. + /// between items of the original iterator. /// - /// The closure will be called exactly once each time an item is placed - /// between two adjacent items from the underlying iterator; specifically, - /// the closure is not called if the underlying iterator yields less than - /// two items and after the last item is yielded. + /// Specifically on fused iterators, it is guaranteed that the new iterator + /// places an item generated by `separator` between adjacent `Some(_)` items. + /// However, for non-fused iterators, [`intersperse_with`] will create a new + /// iterator that is a fused version of the original iterator and place an item + /// generated by `separator` between adjacent `Some(_)` items. This + /// behavior for non-fused iterators is subject to change. + /// + /// The `separator` closure will be called exactly once each time an item + /// is placed between two adjacent items from the underlying iterator; + /// specifically, the closure is not called if the underlying iterator yields + /// less than two items and after the last item is yielded. /// /// If the iterator's item implements [`Clone`], it may be easier to use /// [`intersperse`]. @@ -723,6 +738,7 @@ pub const trait Iterator { /// ``` /// [`Clone`]: crate::clone::Clone /// [`intersperse`]: Iterator::intersperse + /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", issue = "79524")] #[rustc_non_const_trait_method] diff --git a/library/coretests/tests/iter/adapters/intersperse.rs b/library/coretests/tests/iter/adapters/intersperse.rs index 72ae59b6b2f5f..df6be79308be7 100644 --- a/library/coretests/tests/iter/adapters/intersperse.rs +++ b/library/coretests/tests/iter/adapters/intersperse.rs @@ -152,3 +152,203 @@ fn test_try_fold_specialization_intersperse_err() { iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); assert_eq!(iter.next(), None); } + +// FIXME(iter_intersperse): `intersperse` current behavior may change for +// non-fused iterators, so this test will likely have to +// be adjusted; see PR #152855 and issue #79524 +// if `intersperse` doesn't change, remove this FIXME. +#[test] +fn test_non_fused_iterator_intersperse() { + #[derive(Debug)] + struct TestCounter { + counter: usize, + } + + /// Given a counter of 0, this produces: + /// `None` -> `Some(2)` -> `None` -> `Some(4)` -> `None` -> `Some(6)` + /// -> and then `None` endlessly + impl Iterator for TestCounter { + type Item = usize; + fn next(&mut self) -> Option { + if self.counter > 6 { + None + } else if self.counter % 2 == 0 { + self.counter += 1; + None + } else { + self.counter += 1; + Some(self.counter) + } + } + } + + let counter = 0; + // places a 2 between `Some(_)` items + let non_fused_iter = TestCounter { counter }; + let mut intersperse_iter = non_fused_iter.intersperse(2); + // Since `intersperse` currently transforms the original + // iterator into a fused iterator, this intersperse_iter + // should always have `None` + for _ in 0..counter + 6 { + assert_eq!(intersperse_iter.next(), None); + } + + // Extra check to make sure it is `None` after processing 6 items + assert_eq!(intersperse_iter.next(), None); +} + +// FIXME(iter_intersperse): `intersperse` current behavior may change for +// non-fused iterators, so this test will likely have to +// be adjusted; see PR #152855 and issue #79524 +// if `intersperse` doesn't change, remove this FIXME. +#[test] +fn test_non_fused_iterator_intersperse_2() { + #[derive(Debug)] + struct TestCounter { + counter: usize, + } + + // Given a counter of 0, this produces: + // `Some(1)` -> `Some(2)` -> `None` -> `Some(4)` -> `Some(5)` -> + // and then `None` endlessly + impl Iterator for TestCounter { + type Item = usize; + fn next(&mut self) -> Option { + if self.counter < 5 { + self.counter += 1; + if self.counter % 3 != 0 { + return Some(self.counter); + } else { + return None; + } + } + self.counter += 1; + None + } + } + + let counter = 0; + // places a 2 between `Some(_)` items + let non_fused_iter = TestCounter { counter }; + let mut intersperse_iter = non_fused_iter.intersperse(2); + // Since `intersperse` currently transforms the original + // iterator into a fused iterator, this interspersed iter + // will be `Some(1)` -> `Some(2)` -> `Some(2)` -> and then + // `None` endlessly + let mut items_processed = 0; + for num in 0..counter + 6 { + if num < 3 { + if num % 2 != 0 { + assert_eq!(intersperse_iter.next(), Some(2)); + } else { + items_processed += 1; + assert_eq!(intersperse_iter.next(), Some(items_processed)); + } + } else { + assert_eq!(intersperse_iter.next(), None); + } + } + + // Extra check to make sure it is `None` after processing 6 items + assert_eq!(intersperse_iter.next(), None); +} + +// FIXME(iter_intersperse): `intersperse_with` current behavior may change for +// non-fused iterators, so this test will likely have to +// be adjusted; see PR #152855 and issue #79524 +// if `intersperse_with` doesn't change, remove this FIXME. +#[test] +fn test_non_fused_iterator_intersperse_with() { + #[derive(Debug)] + struct TestCounter { + counter: usize, + } + + // Given a counter of 0, this produces: + // `None` -> `Some(2)` -> `None` -> `Some(4)` -> `None` -> `Some(6)` + // -> and then `None` endlessly + impl Iterator for TestCounter { + type Item = usize; + fn next(&mut self) -> Option { + if self.counter > 6 { + None + } else if self.counter % 2 == 0 { + self.counter += 1; + None + } else { + self.counter += 1; + Some(self.counter) + } + } + } + + let counter = 0; + let non_fused_iter = TestCounter { counter }; + // places a 2 between `Some(_)` items + let mut intersperse_iter = non_fused_iter.intersperse_with(|| 2); + // Since `intersperse` currently transforms the original + // iterator into a fused iterator, this intersperse_iter + // should always have `None` + for _ in 0..counter + 6 { + assert_eq!(intersperse_iter.next(), None); + } + + // Extra check to make sure it is `None` after processing 6 items + assert_eq!(intersperse_iter.next(), None); +} + +// FIXME(iter_intersperse): `intersperse_with` current behavior may change for +// non-fused iterators, so this test will likely have to +// be adjusted; see PR #152855 and issue #79524 +// if `intersperse_with` doesn't change, remove this FIXME. +#[test] +fn test_non_fused_iterator_intersperse_with_2() { + #[derive(Debug)] + struct TestCounter { + counter: usize, + } + + // Given a counter of 0, this produces: + // `Some(1)` -> `Some(2)` -> `None` -> `Some(4)` -> `Some(5)` -> + // and then `None` endlessly + impl Iterator for TestCounter { + type Item = usize; + fn next(&mut self) -> Option { + if self.counter < 5 { + self.counter += 1; + if self.counter % 3 != 0 { + return Some(self.counter); + } else { + return None; + } + } + self.counter += 1; + None + } + } + + let counter = 0; + // places a 2 between `Some(_)` items + let non_fused_iter = TestCounter { counter }; + let mut intersperse_iter = non_fused_iter.intersperse(2); + // Since `intersperse` currently transforms the original + // iterator into a fused iterator, this interspersed iter + // will be `Some(1)` -> `Some(2)` -> `Some(2)` -> and then + // `None` endlessly + let mut items_processed = 0; + for num in 0..counter + 6 { + if num < 3 { + if num % 2 != 0 { + assert_eq!(intersperse_iter.next(), Some(2)); + } else { + items_processed += 1; + assert_eq!(intersperse_iter.next(), Some(items_processed)); + } + } else { + assert_eq!(intersperse_iter.next(), None); + } + } + + // Extra check to make sure it is `None` after processing 6 items + assert_eq!(intersperse_iter.next(), None); +} diff --git a/library/std/src/os/hermit/ffi.rs b/library/std/src/os/hermit/ffi.rs index 19761fd99b400..01a54e1ac8df8 100644 --- a/library/std/src/os/hermit/ffi.rs +++ b/library/std/src/os/hermit/ffi.rs @@ -1,4 +1,4 @@ -//! HermitCore-specific extension to the primitives in the `std::ffi` module +//! Hermit-specific extension to the primitives in the `std::ffi` module //! //! # Examples //! diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index db64f8d882e24..f10a090a6e919 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -1,7 +1,7 @@ -//! System bindings for HermitCore +//! System bindings for Hermit //! //! This module contains the facade (aka platform-specific) implementations of -//! OS level functionality for HermitCore. +//! OS level functionality for Hermit. //! //! This is all super highly experimental and not actually intended for //! wide/production use yet, it's still all in the experimental category. This @@ -30,7 +30,7 @@ pub fn unsupported() -> io::Result { } pub fn unsupported_err() -> io::Error { - io::const_error!(io::ErrorKind::Unsupported, "operation not supported on HermitCore yet") + io::const_error!(io::ErrorKind::Unsupported, "operation not supported on Hermit yet") } pub fn abort_internal() -> ! { diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 485af5ab1d016..3ec2bc3af8d42 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -429,7 +429,7 @@ impl fmt::Display for Display<'_> { "freebsd" => "FreeBSD", "fuchsia" => "Fuchsia", "haiku" => "Haiku", - "hermit" => "HermitCore", + "hermit" => "Hermit", "illumos" => "illumos", "ios" => "iOS", "l4re" => "L4Re", diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 375f8338319b6..79dd50c4682de 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -285,7 +285,11 @@ pub(crate) fn create_config( crate_check_cfg: check_cfgs, input, output_file: None, - output_dir: None, + output_dir: if render_options.output_to_stdout { + None + } else { + Some(render_options.output.clone()) + }, file_loader: None, lint_caps, psess_created: None, diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 9a59de4f844ab..3c696f506dd8d 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -682,6 +682,39 @@ pub enum ItemEnum { }, } +impl ItemEnum { + /// Returns the [`ItemKind`] of this item. + pub fn item_kind(&self) -> ItemKind { + match self { + ItemEnum::Module(_) => ItemKind::Module, + ItemEnum::ExternCrate { .. } => ItemKind::ExternCrate, + ItemEnum::Use(_) => ItemKind::Use, + ItemEnum::Union(_) => ItemKind::Union, + ItemEnum::Struct(_) => ItemKind::Struct, + ItemEnum::StructField(_) => ItemKind::StructField, + ItemEnum::Enum(_) => ItemKind::Enum, + ItemEnum::Variant(_) => ItemKind::Variant, + ItemEnum::Function(_) => ItemKind::Function, + ItemEnum::Trait(_) => ItemKind::Trait, + ItemEnum::TraitAlias(_) => ItemKind::TraitAlias, + ItemEnum::Impl(_) => ItemKind::Impl, + ItemEnum::TypeAlias(_) => ItemKind::TypeAlias, + ItemEnum::Constant { .. } => ItemKind::Constant, + ItemEnum::Static(_) => ItemKind::Static, + ItemEnum::ExternType => ItemKind::ExternType, + ItemEnum::Macro(_) => ItemKind::Macro, + ItemEnum::ProcMacro(pm) => match pm.kind { + MacroKind::Bang => ItemKind::Macro, + MacroKind::Attr => ItemKind::ProcAttribute, + MacroKind::Derive => ItemKind::ProcDerive, + }, + ItemEnum::Primitive(_) => ItemKind::Primitive, + ItemEnum::AssocConst { .. } => ItemKind::AssocConst, + ItemEnum::AssocType { .. } => ItemKind::AssocType, + } + } +} + /// A module declaration, e.g. `mod foo;` or `mod foo {}`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Module { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index fdb8e1b475c1d..3620e5425a947 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -242,7 +242,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { !expr_ty_has_significant_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, field.expr)) && match &base { - StructTailExpr::None | StructTailExpr::DefaultFields(_) => true, + StructTailExpr::None | StructTailExpr::NoneWithError(_) | StructTailExpr::DefaultFields(_) => true, StructTailExpr::Base(base) => has_no_effect(cx, base), } }, @@ -353,7 +353,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option Some(base), - StructTailExpr::None | StructTailExpr::DefaultFields(_) => None, + StructTailExpr::None | StructTailExpr::NoneWithError(_) | StructTailExpr::DefaultFields(_) => None, }; Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect()) } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index d5191794b6b06..7ba28f95a719f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -673,7 +673,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, qpath, fields); let base = OptionPat::new(match base { StructTailExpr::Base(base) => Some(self.bind("base", base)), - StructTailExpr::None | StructTailExpr::DefaultFields(_) => None, + StructTailExpr::None | StructTailExpr::NoneWithError(_) | StructTailExpr::DefaultFields(_) => None, }); kind!("Struct({qpath}, {fields}, {base})"); self.qpath(qpath, &expr.name, expr.value.hir_id); diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index b79137c44427e..51b73351fe6a5 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1809,7 +1809,7 @@ fn rewrite_struct_lit<'a>( match struct_rest { ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)), ast::StructRest::Rest(span) => Some(StructLitField::Rest(*span)), - ast::StructRest::None => None, + ast::StructRest::None | ast::StructRest::NoneWithError(_) => None, } .into_iter(), ); diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index 97506cdd592b6..c522ac46d918e 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -1,7 +1,7 @@ #![crate_type = "staticlib"] #![feature(c_variadic)] -use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong}; +use core::ffi::{CStr, VaList, c_char, c_double, c_int, c_long, c_longlong}; macro_rules! continue_if { ($cond:expr) => { @@ -11,12 +11,8 @@ macro_rules! continue_if { }; } -unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { - let cstr0 = CStr::from_ptr(ptr); - match CString::new(val) { - Ok(cstr1) => &*cstr1 == cstr0, - Err(_) => false, - } +unsafe fn compare_c_str(ptr: *const c_char, val: &CStr) -> bool { + val == CStr::from_ptr(ptr) } #[unsafe(no_mangle)] @@ -35,42 +31,42 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { continue_if!(ap.arg::() == ';' as c_int); continue_if!(ap.arg::() == 0x32); continue_if!(ap.arg::() == 0x10000001); - continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!")); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Valid!")); 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { - continue_if!(ap.arg::().floor() == 3.14f64.floor()); + continue_if!(ap.arg::() == 3.14f64); continue_if!(ap.arg::() == 12); continue_if!(ap.arg::() == 'a' as c_int); - continue_if!(ap.arg::().floor() == 6.18f64.floor()); - continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello")); + continue_if!(ap.arg::() == 6.28f64); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Hello")); continue_if!(ap.arg::() == 42); - continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World")); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"World")); 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { - continue_if!(ap.arg::().floor() == 6.28f64.floor()); + continue_if!(ap.arg::() == 6.28f64); continue_if!(ap.arg::() == 16); continue_if!(ap.arg::() == 'A' as c_int); - continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!")); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Skip Me!")); let mut ap = ap.clone(); - if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff } + if compare_c_str(ap.arg::<*const c_char>(), c"Correct") { 0 } else { 0xff } } #[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 42); - continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!")); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Hello, World!")); 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { - continue_if!(ap.arg::().floor() == 3.14f64.floor()); + continue_if!(ap.arg::() == 3.14f64); continue_if!(ap.arg::() == 12); continue_if!(ap.arg::() == 'A' as c_int); continue_if!(ap.arg::() == 1); diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index cca528c425264..96b8ade1f1b16 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -10,7 +10,7 @@ use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; fn main() { - rustc().input("checkrust.rs").run(); + rustc().edition("2021").input("checkrust.rs").run(); cc().input("test.c") .input(static_lib_name("checkrust")) .out_exe("test") diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs index 5d6176b18e886..11901c97fd6a0 100644 --- a/tests/run-make/rustdoc-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-dep-info/rmake.rs @@ -7,6 +7,8 @@ use run_make_support::assertion_helpers::assert_contains; use run_make_support::{path, rfs, rustdoc}; fn main() { + rfs::create_dir("doc"); + // We're only emitting dep info, so we shouldn't be running static analysis to // figure out that this program is erroneous. // Ensure that all kinds of input reading flags end up in dep-info. @@ -20,7 +22,7 @@ fn main() { .emit("dep-info") .run(); - let content = rfs::read_to_string("foo.d"); + let content = rfs::read_to_string("doc/foo.d"); assert_contains(&content, "lib.rs:"); assert_contains(&content, "foo.rs:"); assert_contains(&content, "bar.rs:"); diff --git a/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs b/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs index 00a87477ab5e4..5a612fd130052 100644 --- a/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs @@ -5,15 +5,17 @@ use run_make_support::{assert_contains, rfs}; mod scrape; fn main() { + rfs::create_dir("rustdoc"); + scrape::scrape( &["--scrape-tests", "--emit=dep-info"], &["--emit=dep-info,invocation-specific"], ); - let content = rfs::read_to_string("foobar.d").replace(r"\", "/"); + let content = rfs::read_to_string("rustdoc/foobar.d").replace(r"\", "/"); assert_contains(&content, "lib.rs:"); assert_contains(&content, "rustdoc/ex.calls:"); - let content = rfs::read_to_string("ex.d").replace(r"\", "/"); + let content = rfs::read_to_string("rustdoc/ex.d").replace(r"\", "/"); assert_contains(&content, "examples/ex.rs:"); } diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr index 85f916974e383..8a170201832c9 100644 --- a/tests/ui/const-generics/issues/issue-67185-2.stderr +++ b/tests/ui/const-generics/issues/issue-67185-2.stderr @@ -11,7 +11,6 @@ LL | impl Bar for [u16; 4] {} | ^^^^^^^^^^^^^^^^^^^^^ `[u16; 4]` LL | impl Bar for [[u16; 3]; 3] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `[[u16; 3]; 3]` - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -30,7 +29,6 @@ LL | impl Bar for [u16; 4] {} | ^^^^^^^^^^^^^^^^^^^^^ `[u16; 4]` LL | impl Bar for [[u16; 3]; 3] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `[[u16; 3]; 3]` - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/consts/const-eval/ptr_fragments_in_final.rs b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs index 76f292c3f8b52..7af6a6a9079c4 100644 --- a/tests/ui/consts/const-eval/ptr_fragments_in_final.rs +++ b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs @@ -1,4 +1,5 @@ //! Test that we properly error when there is a pointer fragment in the final value. +//@ ignore-s390x different alignment on s390x make the test fail use std::{mem::{self, MaybeUninit}, ptr}; diff --git a/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr b/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr index de0cd4db7e155..818a559d4e47e 100644 --- a/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr +++ b/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr @@ -1,5 +1,5 @@ error: encountered partial pointer in final value of constant - --> $DIR/ptr_fragments_in_final.rs:15:1 + --> $DIR/ptr_fragments_in_final.rs:16:1 | LL | const MEMCPY_RET: MaybeUninit<*const i32> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | const MEMCPY_RET: MaybeUninit<*const i32> = unsafe { = note: while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value error: encountered partial pointer in final value of constant - --> $DIR/ptr_fragments_in_final.rs:24:1 + --> $DIR/ptr_fragments_in_final.rs:25:1 | LL | const MIXED_PTR: MaybeUninit<*const u8> = { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | const MIXED_PTR: MaybeUninit<*const u8> = { = note: while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value error: encountered partial pointer in final value of constant - --> $DIR/ptr_fragments_in_final.rs:61:5 + --> $DIR/ptr_fragments_in_final.rs:62:5 | LL | const A: Thing = unsafe { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/cross/cross-fn-cache-hole.stderr b/tests/ui/cross/cross-fn-cache-hole.stderr index b7bcbc8933ff4..ca43119dde7f6 100644 --- a/tests/ui/cross/cross-fn-cache-hole.stderr +++ b/tests/ui/cross/cross-fn-cache-hole.stderr @@ -9,7 +9,6 @@ help: this trait has no implementations, consider adding one | LL | trait Bar { } | ^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr index 2c0b466dba3c9..74ccf61bea703 100644 --- a/tests/ui/delegation/generics/impl-to-trait-method.stderr +++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr @@ -14,7 +14,6 @@ help: this trait has no implementations, consider adding one | LL | trait Trait0 {} | ^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 10a7498d5a1c3..e9bee1597c5cd 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -9,7 +9,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -26,7 +25,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -43,7 +41,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -60,7 +57,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -77,7 +73,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -94,7 +89,6 @@ help: the trait `Foo` is implemented for `()` | LL | impl Foo for () where i32: Foo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -106,7 +100,6 @@ error[E0277]: the trait bound `String: Neg` is not satisfied LL | fn use_op(s: String) -> String where String: ::std::ops::Neg { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Neg` is not implemented for `String` | - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -119,7 +112,6 @@ LL | fn use_for() where i32: Iterator { | ^^^^^^^^^^^^^ `i32` is not an iterator | = help: the trait `Iterator` is not implemented for `i32` - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -132,7 +124,6 @@ LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -150,7 +141,6 @@ note: required because it appears within the type `Dst<(dyn A + 'static)>` | LL | struct Dst { | ^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -163,7 +153,6 @@ LL | fn return_str() -> str where str: Sized { | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr index 8ff8f12cdf462..5d19e20757f4c 100644 --- a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr +++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr @@ -4,7 +4,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | String: Copy; | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] @@ -16,7 +15,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | fn demo() -> impl Foo | ^^^^^^^^ the trait `Copy` is not implemented for `String` | - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/issues/auxiliary/issue-14422.rs b/tests/ui/imports/auxiliary/extern-crate-alias-impl-method-aux.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-14422.rs rename to tests/ui/imports/auxiliary/extern-crate-alias-impl-method-aux.rs diff --git a/tests/ui/issues/auxiliary/issue-13620-1.rs b/tests/ui/imports/auxiliary/extern-crate-indirect-fn-ptr-aux-1.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-13620-1.rs rename to tests/ui/imports/auxiliary/extern-crate-indirect-fn-ptr-aux-1.rs diff --git a/tests/ui/imports/auxiliary/extern-crate-indirect-fn-ptr-aux-2.rs b/tests/ui/imports/auxiliary/extern-crate-indirect-fn-ptr-aux-2.rs new file mode 100644 index 0000000000000..f415671fc5a92 --- /dev/null +++ b/tests/ui/imports/auxiliary/extern-crate-indirect-fn-ptr-aux-2.rs @@ -0,0 +1,3 @@ +extern crate extern_crate_indirect_fn_ptr_aux_1 as crate1; + +pub static FOO2: crate1::Foo = crate1::FOO; diff --git a/tests/ui/issues/auxiliary/issue-14344-1.rs b/tests/ui/imports/auxiliary/extern-crate-no-prefer-dynamic-aux-1.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-14344-1.rs rename to tests/ui/imports/auxiliary/extern-crate-no-prefer-dynamic-aux-1.rs diff --git a/tests/ui/imports/auxiliary/extern-crate-no-prefer-dynamic-aux-2.rs b/tests/ui/imports/auxiliary/extern-crate-no-prefer-dynamic-aux-2.rs new file mode 100644 index 0000000000000..001585c34afb8 --- /dev/null +++ b/tests/ui/imports/auxiliary/extern-crate-no-prefer-dynamic-aux-2.rs @@ -0,0 +1,3 @@ +extern crate extern_crate_no_prefer_dynamic_aux_1; + +pub fn bar() {} diff --git a/tests/ui/issues/auxiliary/issue-15562.rs b/tests/ui/imports/auxiliary/extern-transmute-aux.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-15562.rs rename to tests/ui/imports/auxiliary/extern-transmute-aux.rs diff --git a/tests/ui/issues/auxiliary/issue-13507.rs b/tests/ui/imports/auxiliary/typeid-cross-crate-aux.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-13507.rs rename to tests/ui/imports/auxiliary/typeid-cross-crate-aux.rs diff --git a/tests/ui/issues/auxiliary/issue-12612-1.rs b/tests/ui/imports/auxiliary/unused-cross-crate-import-aux-1.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-12612-1.rs rename to tests/ui/imports/auxiliary/unused-cross-crate-import-aux-1.rs diff --git a/tests/ui/issues/auxiliary/issue-12612-2.rs b/tests/ui/imports/auxiliary/unused-cross-crate-import-aux-2.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-12612-2.rs rename to tests/ui/imports/auxiliary/unused-cross-crate-import-aux-2.rs diff --git a/tests/ui/issues/auxiliary/issue-11224.rs b/tests/ui/imports/auxiliary/unused-extern-crate-aux.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-11224.rs rename to tests/ui/imports/auxiliary/unused-extern-crate-aux.rs diff --git a/tests/ui/imports/extern-crate-alias-impl-method.rs b/tests/ui/imports/extern-crate-alias-impl-method.rs new file mode 100644 index 0000000000000..25baa3834cd05 --- /dev/null +++ b/tests/ui/imports/extern-crate-alias-impl-method.rs @@ -0,0 +1,16 @@ +// issue: +// Test that we can call an inherently implemented method via aliasing from an extern crate. +//@ run-pass +#![allow(non_snake_case)] + +//@ aux-build:extern-crate-alias-impl-method-aux.rs + +extern crate extern_crate_alias_impl_method_aux as bug_lib; + +use bug_lib::B; +use bug_lib::make; + +pub fn main() { + let mut an_A: B = make(); + an_A.foo(); +} diff --git a/tests/ui/imports/extern-crate-indirect-fn-ptr.rs b/tests/ui/imports/extern-crate-indirect-fn-ptr.rs new file mode 100644 index 0000000000000..5b88694463496 --- /dev/null +++ b/tests/ui/imports/extern-crate-indirect-fn-ptr.rs @@ -0,0 +1,11 @@ +// issue: +// Test cross crate resolution of an indirect function pointer +//@ run-pass +//@ aux-build:extern-crate-indirect-fn-ptr-aux-1.rs +//@ aux-build:extern-crate-indirect-fn-ptr-aux-2.rs + +extern crate extern_crate_indirect_fn_ptr_aux_2 as crate2; + +fn main() { + (crate2::FOO2.foo)(); +} diff --git a/tests/ui/imports/extern-crate-no-prefer-dynamic.rs b/tests/ui/imports/extern-crate-no-prefer-dynamic.rs new file mode 100644 index 0000000000000..681e7cb599d5c --- /dev/null +++ b/tests/ui/imports/extern-crate-no-prefer-dynamic.rs @@ -0,0 +1,13 @@ +// issue: +// Test that we can depend on an `no-prefer-dynamic` crate. +//@ run-pass +//@ aux-build:extern-crate-no-prefer-dynamic-aux-1.rs +//@ aux-build:extern-crate-no-prefer-dynamic-aux-2.rs + +extern crate extern_crate_no_prefer_dynamic_aux_1; +extern crate extern_crate_no_prefer_dynamic_aux_2; + +fn main() { + extern_crate_no_prefer_dynamic_aux_1::foo(); + extern_crate_no_prefer_dynamic_aux_2::bar(); +} diff --git a/tests/ui/issues/issue-15562.rs b/tests/ui/imports/extern-transmute.rs similarity index 61% rename from tests/ui/issues/issue-15562.rs rename to tests/ui/imports/extern-transmute.rs index d3a8f24c51b7e..18c2530236d54 100644 --- a/tests/ui/issues/issue-15562.rs +++ b/tests/ui/imports/extern-transmute.rs @@ -1,8 +1,9 @@ +// issue: +// Test resolution of `transmute` in an extern block to rust intrinsics. //@ run-pass -//@ aux-build:issue-15562.rs +//@ aux-build:extern-transmute-aux.rs - -extern crate issue_15562 as i; +extern crate extern_transmute_aux as i; pub fn main() { unsafe { diff --git a/tests/ui/issues/issue-13507-2.rs b/tests/ui/imports/typeid-cross-crate.rs similarity index 66% rename from tests/ui/issues/issue-13507-2.rs rename to tests/ui/imports/typeid-cross-crate.rs index afd88a1488153..0b217bde9aee4 100644 --- a/tests/ui/issues/issue-13507-2.rs +++ b/tests/ui/imports/typeid-cross-crate.rs @@ -1,14 +1,16 @@ +// issue: +// Test cross-crate TypeId stability //@ run-pass #![allow(unused_imports)] -//@ aux-build:issue-13507.rs +//@ aux-build:typeid-cross-crate-aux.rs -extern crate issue_13507; -use issue_13507::testtypes; +extern crate typeid_cross_crate_aux; +use typeid_cross_crate_aux::testtypes; use std::any::TypeId; pub fn type_ids() -> Vec { - use issue_13507::testtypes::*; + use typeid_cross_crate_aux::testtypes::*; vec![ TypeId::of::(), TypeId::of::(), @@ -25,12 +27,12 @@ pub fn type_ids() -> Vec { TypeId::of::(), TypeId::of::(), TypeId::of::(), - TypeId::of::() + TypeId::of::(), ] } pub fn main() { - let othercrate = issue_13507::testtypes::type_ids(); + let othercrate = typeid_cross_crate_aux::testtypes::type_ids(); let thiscrate = type_ids(); assert_eq!(thiscrate, othercrate); } diff --git a/tests/ui/imports/unused-cross-crate-import.rs b/tests/ui/imports/unused-cross-crate-import.rs new file mode 100644 index 0000000000000..4e115c3e4445d --- /dev/null +++ b/tests/ui/imports/unused-cross-crate-import.rs @@ -0,0 +1,15 @@ +// issue: +// Test that unused `use` declarations involving multiple external crates are handled properly. +//@ run-pass +#![allow(unused_imports)] +//@ aux-build:unused-cross-crate-import-aux-1.rs +//@ aux-build:unused-cross-crate-import-aux-2.rs + +extern crate unused_cross_crate_import_aux_1 as foo; +extern crate unused_cross_crate_import_aux_2 as bar; + +mod test { + use bar::baz; +} + +fn main() {} diff --git a/tests/ui/imports/unused-extern-crate.rs b/tests/ui/imports/unused-extern-crate.rs new file mode 100644 index 0000000000000..0abfa606d93ad --- /dev/null +++ b/tests/ui/imports/unused-extern-crate.rs @@ -0,0 +1,8 @@ +// issue: +// Test that an unused `extern crate` declaration does not crash the compiler. +//@ run-pass +//@ aux-build:unused-extern-crate-aux.rs + +extern crate unused_extern_crate_aux as unused; + +pub fn main() {} diff --git a/tests/ui/issues/auxiliary/issue-13620-2.rs b/tests/ui/issues/auxiliary/issue-13620-2.rs deleted file mode 100644 index 7efd24407ba9c..0000000000000 --- a/tests/ui/issues/auxiliary/issue-13620-2.rs +++ /dev/null @@ -1,3 +0,0 @@ -extern crate issue_13620_1 as crate1; - -pub static FOO2: crate1::Foo = crate1::FOO; diff --git a/tests/ui/issues/auxiliary/issue-14344-2.rs b/tests/ui/issues/auxiliary/issue-14344-2.rs deleted file mode 100644 index c47b8c0ea6c79..0000000000000 --- a/tests/ui/issues/auxiliary/issue-14344-2.rs +++ /dev/null @@ -1,3 +0,0 @@ -extern crate issue_14344_1; - -pub fn bar() {} diff --git a/tests/ui/issues/issue-11224.rs b/tests/ui/issues/issue-11224.rs deleted file mode 100644 index a7255e6299f98..0000000000000 --- a/tests/ui/issues/issue-11224.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -//@ aux-build:issue-11224.rs - - -extern crate issue_11224 as unused; - -pub fn main() {} diff --git a/tests/ui/issues/issue-11508.rs b/tests/ui/issues/issue-11508.rs deleted file mode 100644 index e7ed7a9f15f1d..0000000000000 --- a/tests/ui/issues/issue-11508.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -//@ aux-build:issue-11508.rs - -extern crate issue_11508 as rand; - -use rand::{Closed01, random}; - -fn main() { - let Closed01(val) = random::>(); - println!("{}", val); -} diff --git a/tests/ui/issues/issue-11552.rs b/tests/ui/issues/issue-11552.rs deleted file mode 100644 index d4784e53e6b41..0000000000000 --- a/tests/ui/issues/issue-11552.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -#![feature(box_patterns)] - -#[derive(Clone)] -enum Noun -{ - Atom(isize), - Cell(Box, Box) -} - -fn fas(n: &Noun) -> Noun -{ - match n { - &Noun::Cell(box Noun::Atom(2), box Noun::Cell(ref a, _)) => (**a).clone(), - _ => panic!("Invalid fas pattern") - } -} - -pub fn main() { - fas( - &Noun::Cell(Box::new(Noun::Atom(2)), - Box::new(Noun::Cell(Box::new(Noun::Atom(2)), Box::new(Noun::Atom(3))))) - ); -} diff --git a/tests/ui/issues/issue-11592.rs b/tests/ui/issues/issue-11592.rs deleted file mode 100644 index cb1a92e809a9d..0000000000000 --- a/tests/ui/issues/issue-11592.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ check-pass -//! Ensure the private trait Bar isn't complained about. - -#![deny(missing_docs)] - -mod foo { - trait Bar { fn bar(&self) { } } - impl Bar for i8 { fn bar(&self) { } } -} - -fn main() { } diff --git a/tests/ui/issues/issue-11677.rs b/tests/ui/issues/issue-11677.rs deleted file mode 100644 index 32e129b2c01d6..0000000000000 --- a/tests/ui/issues/issue-11677.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass -#![allow(unused_imports)] - -#![allow(dead_code)] - -// this code used to cause an ICE - -use std::marker; - -trait X { - fn dummy(&self) -> T { panic!() } -} - -struct S {f: Box+'static>, - g: Box+'static>} - -struct F; -impl X for F { -} - -fn main() { - S {f: Box::new(F), g: Box::new(F) }; -} diff --git a/tests/ui/issues/issue-12612.rs b/tests/ui/issues/issue-12612.rs deleted file mode 100644 index ec0f3926aa5d3..0000000000000 --- a/tests/ui/issues/issue-12612.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -#![allow(unused_imports)] -//@ aux-build:issue-12612-1.rs -//@ aux-build:issue-12612-2.rs - - -extern crate issue_12612_1 as foo; -extern crate issue_12612_2 as bar; - -mod test { - use bar::baz; -} - -fn main() {} diff --git a/tests/ui/issues/issue-13620.rs b/tests/ui/issues/issue-13620.rs deleted file mode 100644 index 4d9db3aa7ceda..0000000000000 --- a/tests/ui/issues/issue-13620.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ aux-build:issue-13620-1.rs -//@ aux-build:issue-13620-2.rs - - -extern crate issue_13620_2 as crate2; - -fn main() { - (crate2::FOO2.foo)(); -} diff --git a/tests/ui/issues/issue-14344.rs b/tests/ui/issues/issue-14344.rs deleted file mode 100644 index 17863c7809ea6..0000000000000 --- a/tests/ui/issues/issue-14344.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -//@ aux-build:issue-14344-1.rs -//@ aux-build:issue-14344-2.rs - -extern crate issue_14344_1; -extern crate issue_14344_2; - -fn main() { - issue_14344_1::foo(); - issue_14344_2::bar(); -} diff --git a/tests/ui/issues/issue-14422.rs b/tests/ui/issues/issue-14422.rs deleted file mode 100644 index b7bb2caa7f088..0000000000000 --- a/tests/ui/issues/issue-14422.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -#![allow(non_snake_case)] - -//@ aux-build:issue-14422.rs - - -extern crate issue_14422 as bug_lib; - -use bug_lib::B; -use bug_lib::make; - -pub fn main() { - let mut an_A: B = make(); - an_A.foo(); -} diff --git a/tests/ui/lint/missing-docs-private-trait.rs b/tests/ui/lint/missing-docs-private-trait.rs new file mode 100644 index 0000000000000..dde4dc2a02680 --- /dev/null +++ b/tests/ui/lint/missing-docs-private-trait.rs @@ -0,0 +1,17 @@ +// issue: +// Test that the `missing_docs` lint does not trigger for a private trait. +//@ check-pass +//! Ensure the private trait Bar isn't complained about. + +#![deny(missing_docs)] + +mod foo { + trait Bar { + fn bar(&self) {} + } + impl Bar for i8 { + fn bar(&self) {} + } +} + +fn main() {} diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 9800420072be4..5c50a580fd148 100644 --- a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -88,7 +88,6 @@ error[E0277]: the trait bound `X: Eq` is not satisfied LL | type W: Ord where Self: Eq; | ^^^^^^^^ the trait `Eq` is not implemented for `X` | - = help: see issue #48214 help: consider annotating `X` with `#[derive(Eq)]` | LL + #[derive(Eq)] @@ -105,7 +104,6 @@ error[E0277]: the trait bound `X: Eq` is not satisfied LL | type W where Self: Eq; | ^^^^^^^^ the trait `Eq` is not implemented for `X` | - = help: see issue #48214 help: consider annotating `X` with `#[derive(Eq)]` | LL + #[derive(Eq)] diff --git a/tests/ui/parser/issues/issue-102806.rs b/tests/ui/parser/issues/issue-102806.rs index 5ee8c5c1e3de0..804e727272d4c 100644 --- a/tests/ui/parser/issues/issue-102806.rs +++ b/tests/ui/parser/issues/issue-102806.rs @@ -16,7 +16,6 @@ fn pz(v: V3) { let _ = V3 { z: 0.0, ... }; //~^ ERROR expected identifier - //~| ERROR missing fields `x` and `y` in initializer of `V3` let V3 { z: val, ... } = v; //~^ ERROR expected field pattern diff --git a/tests/ui/parser/issues/issue-102806.stderr b/tests/ui/parser/issues/issue-102806.stderr index cd447c6dec0d2..d4c899ed58114 100644 --- a/tests/ui/parser/issues/issue-102806.stderr +++ b/tests/ui/parser/issues/issue-102806.stderr @@ -31,7 +31,7 @@ LL | let _ = V3 { z: 0.0, ... }; | while parsing this struct error: expected field pattern, found `...` - --> $DIR/issue-102806.rs:21:22 + --> $DIR/issue-102806.rs:20:22 | LL | let V3 { z: val, ... } = v; | ^^^ @@ -42,12 +42,5 @@ LL - let V3 { z: val, ... } = v; LL + let V3 { z: val, .. } = v; | -error[E0063]: missing fields `x` and `y` in initializer of `V3` - --> $DIR/issue-102806.rs:17:13 - | -LL | let _ = V3 { z: 0.0, ... }; - | ^^ missing `x` and `y` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/parser/issues/issue-52496.rs b/tests/ui/parser/issues/issue-52496.rs index 05461f8b8c413..3e88a92aae9bf 100644 --- a/tests/ui/parser/issues/issue-52496.rs +++ b/tests/ui/parser/issues/issue-52496.rs @@ -7,6 +7,5 @@ fn main() { let bar = 1.5f32; let _ = Foo { bar.into(), bat: -1, . }; //~^ ERROR expected one of - //~| ERROR missing fields `bar` and `baz` in initializer of `Foo` //~| ERROR expected identifier, found `.` } diff --git a/tests/ui/parser/issues/issue-52496.stderr b/tests/ui/parser/issues/issue-52496.stderr index a97effb4e0cd8..da22f5ce13562 100644 --- a/tests/ui/parser/issues/issue-52496.stderr +++ b/tests/ui/parser/issues/issue-52496.stderr @@ -37,12 +37,6 @@ error[E0063]: missing field `bat` in initializer of `Foo` LL | let _ = Foo { bar: .5, baz: 42 }; | ^^^ missing `bat` -error[E0063]: missing fields `bar` and `baz` in initializer of `Foo` - --> $DIR/issue-52496.rs:8:13 - | -LL | let _ = Foo { bar.into(), bat: -1, . }; - | ^^^ missing `bar` and `baz` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-with-2.rs b/tests/ui/parser/removed-syntax/removed-syntax-with-2.rs index 451057c66a127..119afdcc75e36 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-with-2.rs +++ b/tests/ui/parser/removed-syntax/removed-syntax-with-2.rs @@ -7,5 +7,4 @@ fn main() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; //~^ ERROR expected one of `,`, `:`, or `}`, found `a` - //~| ERROR missing field `bar` in initializer of `S` } diff --git a/tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr b/tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr index e75c5bcd64319..7768aeccfad99 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-with-2.stderr @@ -7,12 +7,5 @@ LL | let b = S { foo: (), with a }; | | while parsing this struct field | while parsing this struct -error[E0063]: missing field `bar` in initializer of `S` - --> $DIR/removed-syntax-with-2.rs:8:13 - | -LL | let b = S { foo: (), with a }; - | ^ missing `bar` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/parser/struct-field-numeric-shorthand.rs b/tests/ui/parser/struct-field-numeric-shorthand.rs index 645abd9c7192d..aa342eb02a916 100644 --- a/tests/ui/parser/struct-field-numeric-shorthand.rs +++ b/tests/ui/parser/struct-field-numeric-shorthand.rs @@ -5,5 +5,4 @@ fn main() { //~^ ERROR expected identifier, found `0` //~| ERROR expected identifier, found `1` //~| ERROR expected identifier, found `2` - //~| ERROR missing fields `0`, `1` and `2` in initializer of `Rgb` } diff --git a/tests/ui/parser/struct-field-numeric-shorthand.stderr b/tests/ui/parser/struct-field-numeric-shorthand.stderr index bfb8a931b6406..9878cfbbdceb8 100644 --- a/tests/ui/parser/struct-field-numeric-shorthand.stderr +++ b/tests/ui/parser/struct-field-numeric-shorthand.stderr @@ -22,12 +22,5 @@ LL | let _ = Rgb { 0, 1, 2 }; | | | while parsing this struct -error[E0063]: missing fields `0`, `1` and `2` in initializer of `Rgb` - --> $DIR/struct-field-numeric-shorthand.rs:4:13 - | -LL | let _ = Rgb { 0, 1, 2 }; - | ^^^ missing `0`, `1` and `2` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/issues/auxiliary/issue-11508.rs b/tests/ui/pattern/auxiliary/tuple-struct-cross-crate-aux.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-11508.rs rename to tests/ui/pattern/auxiliary/tuple-struct-cross-crate-aux.rs diff --git a/tests/ui/pattern/box-pattern-nested.rs b/tests/ui/pattern/box-pattern-nested.rs new file mode 100644 index 0000000000000..f686fee8742ce --- /dev/null +++ b/tests/ui/pattern/box-pattern-nested.rs @@ -0,0 +1,24 @@ +// issue: +// Test nested box pattern matching inside a larger `match` statement. +//@ run-pass +#![feature(box_patterns)] + +#[derive(Clone)] +enum Noun { + Atom(isize), + Cell(Box, Box), +} + +fn fas(n: &Noun) -> Noun { + match n { + &Noun::Cell(box Noun::Atom(2), box Noun::Cell(ref a, _)) => (**a).clone(), + _ => panic!("Invalid fas pattern"), + } +} + +pub fn main() { + fas(&Noun::Cell( + Box::new(Noun::Atom(2)), + Box::new(Noun::Cell(Box::new(Noun::Atom(2)), Box::new(Noun::Atom(3)))), + )); +} diff --git a/tests/ui/pattern/tuple-struct-cross-crate.rs b/tests/ui/pattern/tuple-struct-cross-crate.rs new file mode 100644 index 0000000000000..fd1158d44bdb0 --- /dev/null +++ b/tests/ui/pattern/tuple-struct-cross-crate.rs @@ -0,0 +1,13 @@ +// issue: +// Test pattern matching on a tuple struct defined in an external crate. +//@ run-pass +//@ aux-build:tuple-struct-cross-crate-aux.rs + +extern crate tuple_struct_cross_crate_aux as rand; + +use rand::{Closed01, random}; + +fn main() { + let Closed01(val) = random::>(); + println!("{}", val); +} diff --git a/tests/ui/structs/syntax-error-not-missing-field.rs b/tests/ui/structs/syntax-error-not-missing-field.rs new file mode 100644 index 0000000000000..f1080d3908cf4 --- /dev/null +++ b/tests/ui/structs/syntax-error-not-missing-field.rs @@ -0,0 +1,38 @@ +// Check that a syntax error inside a struct literal does not also report missing fields, +// because the field might be present but hidden by the syntax error. +// +// The stderr for this test should contain ONLY one syntax error per struct literal, +// and not any errors about missing fields. + +struct Foo { a: isize, b: isize } + +fn make_a() -> isize { 1234 } + +fn expr_wrong_separator() { + let f = Foo { a: make_a(); b: 2 }; //~ ERROR found `;` +} + +fn expr_missing_separator() { + let f = Foo { a: make_a() b: 2 }; //~ ERROR found `b` +} + +fn expr_rest_trailing_comma() { + let f = Foo { a: make_a(), ..todo!(), }; //~ ERROR cannot use a comma +} + +fn expr_missing_field_name() { + let f = Foo { make_a(), b: 2, }; //~ ERROR found `(` +} + +fn pat_wrong_separator(Foo { a; b }: Foo) { //~ ERROR expected `,` + let _ = (a, b); +} + +fn pat_missing_separator(Foo { a b }: Foo) { //~ ERROR expected `,` + let _ = (a, b); +} + +fn pat_rest_trailing_comma(Foo { a, .., }: Foo) { //~ ERROR expected `}`, found `,` +} + +fn main() {} diff --git a/tests/ui/structs/syntax-error-not-missing-field.stderr b/tests/ui/structs/syntax-error-not-missing-field.stderr new file mode 100644 index 0000000000000..d781a41300f36 --- /dev/null +++ b/tests/ui/structs/syntax-error-not-missing-field.stderr @@ -0,0 +1,74 @@ +error: expected one of `,`, `.`, `?`, `}`, or an operator, found `;` + --> $DIR/syntax-error-not-missing-field.rs:12:30 + | +LL | let f = Foo { a: make_a(); b: 2 }; + | --- ^ + | | | + | | expected one of `,`, `.`, `?`, `}`, or an operator + | | help: try adding a comma: `,` + | while parsing this struct + +error: expected one of `,`, `.`, `?`, `}`, or an operator, found `b` + --> $DIR/syntax-error-not-missing-field.rs:16:31 + | +LL | let f = Foo { a: make_a() b: 2 }; + | --- -^ expected one of `,`, `.`, `?`, `}`, or an operator + | | | + | | help: try adding a comma: `,` + | while parsing this struct + +error: cannot use a comma after the base struct + --> $DIR/syntax-error-not-missing-field.rs:20:32 + | +LL | let f = Foo { a: make_a(), ..todo!(), }; + | ^^^^^^^^^ + | + = note: the base struct must always be the last field +help: remove this comma + | +LL - let f = Foo { a: make_a(), ..todo!(), }; +LL + let f = Foo { a: make_a(), ..todo!() }; + | + +error: expected one of `,`, `:`, or `}`, found `(` + --> $DIR/syntax-error-not-missing-field.rs:24:25 + | +LL | let f = Foo { make_a(), b: 2, }; + | --- ------^ expected one of `,`, `:`, or `}` + | | | + | | while parsing this struct field + | while parsing this struct + | +help: try naming a field + | +LL | let f = Foo { make_a: make_a(), b: 2, }; + | +++++++ + +error: expected `,` + --> $DIR/syntax-error-not-missing-field.rs:27:31 + | +LL | fn pat_wrong_separator(Foo { a; b }: Foo) { + | --- ^ + | | + | while parsing the fields for this pattern + +error: expected `,` + --> $DIR/syntax-error-not-missing-field.rs:31:34 + | +LL | fn pat_missing_separator(Foo { a b }: Foo) { + | --- ^ + | | + | while parsing the fields for this pattern + +error: expected `}`, found `,` + --> $DIR/syntax-error-not-missing-field.rs:35:39 + | +LL | fn pat_rest_trailing_comma(Foo { a, .., }: Foo) { + | --^ + | | | + | | expected `}` + | | help: remove this comma + | `..` must be at the end and cannot have a trailing comma + +error: aborting due to 7 previous errors + diff --git a/tests/ui/suggestions/struct-initializer-comma.fixed b/tests/ui/suggestions/struct-initializer-comma.fixed index 556bfbca58df4..9bd9434a3b59d 100644 --- a/tests/ui/suggestions/struct-initializer-comma.fixed +++ b/tests/ui/suggestions/struct-initializer-comma.fixed @@ -7,7 +7,6 @@ pub struct Foo { fn main() { let _ = Foo { - //~^ ERROR missing field first: true, second: 25 //~^ ERROR expected one of diff --git a/tests/ui/suggestions/struct-initializer-comma.rs b/tests/ui/suggestions/struct-initializer-comma.rs index 7b93bf187b870..4b225df08df0a 100644 --- a/tests/ui/suggestions/struct-initializer-comma.rs +++ b/tests/ui/suggestions/struct-initializer-comma.rs @@ -7,7 +7,6 @@ pub struct Foo { fn main() { let _ = Foo { - //~^ ERROR missing field first: true second: 25 //~^ ERROR expected one of diff --git a/tests/ui/suggestions/struct-initializer-comma.stderr b/tests/ui/suggestions/struct-initializer-comma.stderr index 5eff43f32cda1..5fdc95a30cc44 100644 --- a/tests/ui/suggestions/struct-initializer-comma.stderr +++ b/tests/ui/suggestions/struct-initializer-comma.stderr @@ -1,9 +1,8 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `second` - --> $DIR/struct-initializer-comma.rs:12:9 + --> $DIR/struct-initializer-comma.rs:11:9 | LL | let _ = Foo { | --- while parsing this struct -LL | LL | first: true | - | | @@ -12,12 +11,5 @@ LL | first: true LL | second: 25 | ^^^^^^ unexpected token -error[E0063]: missing field `second` in initializer of `Foo` - --> $DIR/struct-initializer-comma.rs:9:13 - | -LL | let _ = Foo { - | ^^^ missing `second` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index 780535283a3a9..11d764d111eed 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -77,7 +77,6 @@ help: this trait has no implementations, consider adding one | LL | trait Sub: Super {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | LL + #![feature(trivial_bounds)] diff --git a/tests/ui/typeck/infer-struct-with-trait-object.rs b/tests/ui/typeck/infer-struct-with-trait-object.rs new file mode 100644 index 0000000000000..c6de73a69dc0c --- /dev/null +++ b/tests/ui/typeck/infer-struct-with-trait-object.rs @@ -0,0 +1,27 @@ +// issue: +// Test that type inference works correctly for struct fields containing trait objects. +//@ run-pass +#![allow(unused_imports)] +#![allow(dead_code)] + +// this code used to cause an ICE + +use std::marker; + +trait X { + fn dummy(&self) -> T { + panic!() + } +} + +struct S { + f: Box + 'static>, + g: Box + 'static>, +} + +struct F; +impl X for F {} + +fn main() { + S { f: Box::new(F), g: Box::new(F) }; +}