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