From 2c752bcf559975995eb8086a7fa6a7f9b5ba0de8 Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Thu, 20 Feb 2025 11:47:14 -0600 Subject: [PATCH 01/40] Undeprecate env::home_dir --- library/std/src/env.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index adbd68896241c..5a931b077cdb0 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -641,11 +641,6 @@ impl Error for JoinPathsError { /// None => println!("Impossible to get your home dir!"), /// } /// ``` -#[deprecated( - since = "1.29.0", - note = "This function's behavior may be unexpected on Windows. \ - Consider using a crate from crates.io instead." -)] #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { From 812b1dec4abb52a38652956d8b82d9bbe0162999 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 20 Feb 2025 18:18:01 -0800 Subject: [PATCH 02/40] ref_pat_eat_one_layer_2024: add context and examples to the unstable book --- .../ref-pat-eat-one-layer-2024-structural.md | 26 +++++++++++++++--- .../ref-pat-eat-one-layer-2024.md | 27 ++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md index bfdb579cd3523..b2f59732801bc 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md @@ -9,12 +9,32 @@ The tracking issue for this feature is: [#123076] This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion -in Rust. -For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for -[Editions 2024 and later]. +in Rust, allowing `&` patterns in more places. For example: +```rust,edition2024 +#![feature(ref_pat_eat_one_layer_2024_structural)] +#![allow(incomplete_features)] +# +# // Tests type equality in a way that avoids coercing `&&T` or `&mut T` to `&T`. +# trait Eq {} +# impl Eq for T {} +# fn has_type(_: impl Eq) {} + +// `&` can match against a `ref` binding mode instead of a reference type: +let (x, &y) = &(0, 1); +has_type::<&u8>(x); +has_type::(y); + +// `&` can match against `&mut` references: +let &z = &mut 2; +has_type::(z); +``` + +For specifics, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For more information on binding modes, see [The Rust Reference]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md). [Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQEBAAAAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false +[The Rust Reference]: https://doc.rust-lang.org/reference/patterns.html#binding-modes diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md index 0c90cec0dbddb..f7c85eec2d28e 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md @@ -9,12 +9,33 @@ The tracking issue for this feature is: [#123076] This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion -in Rust. -For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for -[Editions 2024 and later]. +in Rust, allowing `&` patterns in more places. For example: + +```rust,edition2024 +#![feature(ref_pat_eat_one_layer_2024)] +#![allow(incomplete_features)] +# +# // Tests type equality in a way that avoids coercing `&&T` or `&mut T` to `&T`. +# trait Eq {} +# impl Eq for T {} +# fn has_type(_: impl Eq) {} + +// `&` can match against a `ref` binding mode instead of a reference type: +let (x, &y) = &(0, 1); +has_type::<&u8>(x); +has_type::(y); + +// `&` can match against `&mut` references: +let &z = &mut 2; +has_type::(z); +``` + +For specifics, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For more information on binding modes, see [The Rust Reference]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md). [Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false +[The Rust Reference]: https://doc.rust-lang.org/reference/patterns.html#binding-modes From 9323ba54d3b35aeaf55a9596a29682c7173cf4d2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Feb 2025 03:04:13 +0000 Subject: [PATCH 03/40] Remove MaybeForgetReturn suggestion --- compiler/rustc_errors/src/lib.rs | 1 - .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 5 -- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 60 +------------------ .../src/error_reporting/traits/ambiguity.rs | 8 +-- ...suggest-add-return-to-coerce-ret-ty.stderr | 8 --- .../return/tail-expr-as-potential-return.rs | 1 - .../tail-expr-as-potential-return.stderr | 4 -- 7 files changed, 4 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6fce1fade2664..9df306bb63540 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -599,7 +599,6 @@ pub enum StashKey { MaybeFruTypo, CallAssocMethod, AssociatedTypeSuggestion, - MaybeForgetReturn, /// Query cycle detected, stashing in favor of a better error. Cycle, UndeterminedMacroResolution, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2d7d80e39bc31..5bd190cda9503 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -666,12 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); - let errors_causecode = errors - .iter() - .map(|e| (e.obligation.cause.span, e.root_obligation.cause.code().clone())) - .collect::>(); self.err_ctxt().report_fulfillment_errors(errors); - self.collect_unused_stmts_for_coerce_return_ty(errors_causecode); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index cf61659479b13..f1b60fabfefd9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -3,9 +3,7 @@ use std::{fmt, iter, mem}; use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; -use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize, -}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -2167,62 +2165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(super) fn collect_unused_stmts_for_coerce_return_ty( - &self, - errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>, - ) { - for (span, code) in errors_causecode { - self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| { - if let Some(fn_sig) = self.body_fn_sig() - && let ObligationCauseCode::WhereClauseInExpr(_, _, binding_hir_id, ..) = code - && !fn_sig.output().is_unit() - { - let mut block_num = 0; - let mut found_semi = false; - for (hir_id, node) in self.tcx.hir_parent_iter(binding_hir_id) { - // Don't proceed into parent bodies - if hir_id.owner != binding_hir_id.owner { - break; - } - match node { - hir::Node::Stmt(stmt) => { - if let hir::StmtKind::Semi(expr) = stmt.kind { - let expr_ty = self.typeck_results.borrow().expr_ty(expr); - let return_ty = fn_sig.output(); - if !matches!(expr.kind, hir::ExprKind::Ret(..)) - && self.may_coerce(expr_ty, return_ty) - { - found_semi = true; - } - } - } - hir::Node::Block(_block) => { - if found_semi { - block_num += 1; - } - } - hir::Node::Item(item) => { - if let hir::ItemKind::Fn { .. } = item.kind { - break; - } - } - _ => {} - } - } - if block_num > 1 && found_semi { - err.span_suggestion_verbose( - // use the span of the *whole* expr - self.tcx.hir().span(binding_hir_id).shrink_to_lo(), - "you might have meant to return this to infer its type parameters", - "return ", - Applicability::MaybeIncorrect, - ); - } - } - }); - } - } - /// Given a vector of fulfillment errors, try to adjust the spans of the /// errors to more accurately point at the cause of the failure. /// diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index f15f1b78b5282..d673e5672a00b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -1,8 +1,6 @@ use std::ops::ControlFlow; -use rustc_errors::{ - Applicability, Diag, E0283, E0284, E0790, MultiSpan, StashKey, struct_span_code_err, -}; +use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def::{DefKind, Res}; @@ -197,7 +195,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // be ignoring the fact that we don't KNOW the type works // out. Though even that would probably be harmless, given that // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // inhabited. We used to check for `self.tainted_by_errors()` to // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. @@ -211,7 +209,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeAnnotationNeeded::E0282, false, ); - return err.stash(span, StashKey::MaybeForgetReturn).unwrap(); + return err.emit(); } Some(e) => return e, } diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr index 1fea73529a8a2..c61ca699b0d35 100644 --- a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr +++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr @@ -8,10 +8,6 @@ help: consider specifying the generic arguments | LL | Err::(MyError); | ++++++++++++++ -help: you might have meant to return this to infer its type parameters - | -LL | return Err(MyError); - | ++++++ error[E0282]: type annotations needed --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9 @@ -23,10 +19,6 @@ help: consider specifying the generic arguments | LL | Ok::<(), E>(()); | +++++++++ -help: you might have meant to return this to infer its type parameters - | -LL | return Ok(()); - | ++++++ error[E0308]: mismatched types --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20 diff --git a/tests/ui/return/tail-expr-as-potential-return.rs b/tests/ui/return/tail-expr-as-potential-return.rs index 11ecddb049b57..2e638f1897c22 100644 --- a/tests/ui/return/tail-expr-as-potential-return.rs +++ b/tests/ui/return/tail-expr-as-potential-return.rs @@ -60,7 +60,6 @@ fn method() -> Option { Receiver.generic(); //~^ ERROR type annotations needed //~| HELP consider specifying the generic argument - //~| HELP you might have meant to return this to infer its type parameters } None diff --git a/tests/ui/return/tail-expr-as-potential-return.stderr b/tests/ui/return/tail-expr-as-potential-return.stderr index 756de2b5a1668..8105b2df3fea6 100644 --- a/tests/ui/return/tail-expr-as-potential-return.stderr +++ b/tests/ui/return/tail-expr-as-potential-return.stderr @@ -57,10 +57,6 @@ help: consider specifying the generic argument | LL | Receiver.generic::(); | +++++ -help: you might have meant to return this to infer its type parameters - | -LL | return Receiver.generic(); - | ++++++ error: aborting due to 4 previous errors From a7bd4a309c2d154ab4bafee9b575d4196b5d3222 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 25 Feb 2025 22:26:52 +0000 Subject: [PATCH 04/40] Add DWARF test case for non-C-like `repr128` enums --- tests/run-make/repr128-dwarf/main.rs | 25 ++++++ tests/run-make/repr128-dwarf/rmake.rs | 115 +++++++++++++++++++++----- 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/tests/run-make/repr128-dwarf/main.rs b/tests/run-make/repr128-dwarf/main.rs index 57923a8386db9..9842ab4a3426f 100644 --- a/tests/run-make/repr128-dwarf/main.rs +++ b/tests/run-make/repr128-dwarf/main.rs @@ -19,8 +19,33 @@ pub enum I128Enum { I128D = i128::MAX.to_le(), } +#[cfg(not(old_llvm))] +#[repr(u128)] +pub enum U128VariantEnum { + VariantU128A(u8) = 0_u128.to_le(), + VariantU128B = 1_u128.to_le(), + VariantU128C = (u64::MAX as u128 + 1).to_le(), + VariantU128D = u128::MAX.to_le(), +} + +#[cfg(not(old_llvm))] +#[repr(i128)] +pub enum I128VariantEnum { + VariantI128A(u8) = 0_i128.to_le(), + VariantI128B = (-1_i128).to_le(), + VariantI128C = i128::MIN.to_le(), + VariantI128D = i128::MAX.to_le(), +} + pub fn f(_: U128Enum, _: I128Enum) {} +#[cfg(not(old_llvm))] +pub fn g(_: U128VariantEnum, _: I128VariantEnum) {} + fn main() { f(U128Enum::U128A, I128Enum::I128A); + #[cfg(not(old_llvm))] + { + g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2)); + } } diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 2fd54c186b934..15eb186717f6d 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -5,13 +5,32 @@ use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; +use gimli::read::DebuggingInformationEntry; use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; use run_make_support::{gimli, object, rfs, rustc}; fn main() { + // Before LLVM 20, 128-bit enums with variants didn't emit debuginfo correctly. + // This check can be removed once Rust no longer supports LLVM 18 and 19. + let llvm_version = rustc() + .verbose() + .arg("--version") + .run() + .stdout_utf8() + .lines() + .filter_map(|line| line.strip_prefix("LLVM version: ")) + .map(|version| version.split(".").next().unwrap().parse::().unwrap()) + .next() + .unwrap(); + let is_old_llvm = llvm_version < 20; + let output = PathBuf::from("repr128"); - rustc().input("main.rs").output(&output).arg("-Cdebuginfo=2").run(); + let mut rustc = rustc(); + if is_old_llvm { + rustc.cfg("old_llvm"); + } + rustc.input("main.rs").output(&output).arg("-Cdebuginfo=2").run(); // Mach-O uses packed debug info let dsym_location = output .with_extension("dSYM") @@ -29,7 +48,8 @@ fn main() { }) .unwrap(); let mut iter = dwarf.units(); - let mut still_to_find = HashMap::from([ + + let mut enumerators_to_find = HashMap::from([ ("U128A", 0_u128), ("U128B", 1_u128), ("U128C", u64::MAX as u128 + 1), @@ -39,35 +59,88 @@ fn main() { ("I128C", i128::MIN as u128), ("I128D", i128::MAX as u128), ]); + let mut variants_to_find = HashMap::from([ + ("VariantU128A", 0_u128), + ("VariantU128B", 1_u128), + ("VariantU128C", u64::MAX as u128 + 1), + ("VariantU128D", u128::MAX), + ("VariantI128A", 0_i128 as u128), + ("VariantI128B", (-1_i128) as u128), + ("VariantI128C", i128::MIN as u128), + ("VariantI128D", i128::MAX as u128), + ]); + while let Some(header) = iter.next().unwrap() { let unit = dwarf.unit(header).unwrap(); let mut cursor = unit.entries(); + + let get_name = |entry: &DebuggingInformationEntry<'_, '_, _>| { + let name = dwarf + .attr_string( + &unit, + entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(), + ) + .unwrap(); + name.to_string().unwrap().to_string() + }; + while let Some((_, entry)) = cursor.next_dfs().unwrap() { - if entry.tag() == gimli::constants::DW_TAG_enumerator { - let name = dwarf - .attr_string( - &unit, - entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(), - ) - .unwrap(); - let name = name.to_string().unwrap(); - if let Some(expected) = still_to_find.remove(name.as_ref()) { - match entry.attr(gimli::constants::DW_AT_const_value).unwrap().unwrap().value() + match entry.tag() { + gimli::constants::DW_TAG_variant if !is_old_llvm => { + let value = match entry + .attr(gimli::constants::DW_AT_discr_value) + .unwrap() + .unwrap() + .value() { - AttributeValue::Block(value) => { - assert_eq!( - value.to_slice().unwrap(), - expected.to_le_bytes().as_slice(), - "{name}" - ); + AttributeValue::Block(value) => value.to_slice().unwrap().to_vec(), + value => panic!("unexpected DW_AT_discr_value of {value:?}"), + }; + // The `DW_TAG_member` that is a child of `DW_TAG_variant` will contain the + // variant's name. + let Some((1, child_entry)) = cursor.next_dfs().unwrap() else { + panic!("Missing child of DW_TAG_variant"); + }; + assert_eq!(child_entry.tag(), gimli::constants::DW_TAG_member); + let name = get_name(child_entry); + if let Some(expected) = variants_to_find.remove(name.as_str()) { + // This test uses LE byte order is used for consistent values across + // architectures. + assert_eq!(value.as_slice(), expected.to_le_bytes().as_slice(), "{name}"); + } + } + + gimli::constants::DW_TAG_enumerator => { + let name = get_name(entry); + if let Some(expected) = enumerators_to_find.remove(name.as_str()) { + match entry + .attr(gimli::constants::DW_AT_const_value) + .unwrap() + .unwrap() + .value() + { + AttributeValue::Block(value) => { + // This test uses LE byte order is used for consistent values across + // architectures. + assert_eq!( + value.to_slice().unwrap(), + expected.to_le_bytes().as_slice(), + "{name}" + ); + } + value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"), } - value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"), } } + + _ => {} } } } - if !still_to_find.is_empty() { - panic!("Didn't find debug entries for {still_to_find:?}"); + if !enumerators_to_find.is_empty() { + panic!("Didn't find debug enumerator entries for {enumerators_to_find:?}"); + } + if !is_old_llvm && !variants_to_find.is_empty() { + panic!("Didn't find debug variant entries for {variants_to_find:?}"); } } From fb3aa33418fcca981493a60f4c2a1c8558ddca93 Mon Sep 17 00:00:00 2001 From: Niels Saurer Date: Thu, 27 Feb 2025 18:32:09 +0100 Subject: [PATCH 05/40] Revert "Derive `Clone` on fewer THIR types." This reverts commit f0b6d660c9c13ab7b19da9e12aeb4dcab45e544b. --- compiler/rustc_middle/src/thir.rs | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e5592de81cd78..fabee391ac678 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -19,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::{IndexVec, newtype_index}; -use rustc_macros::{HashStable, TypeVisitable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -52,7 +52,7 @@ macro_rules! thir_with_elements { /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). - #[derive(Debug, HashStable)] + #[derive(Debug, HashStable, Clone)] pub struct Thir<'tcx> { pub body_type: BodyTy<'tcx>, $( @@ -90,7 +90,7 @@ thir_with_elements! { params: ParamId => Param<'tcx> => "p{}", } -#[derive(Debug, HashStable)] +#[derive(Debug, HashStable, Clone)] pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), @@ -98,7 +98,7 @@ pub enum BodyTy<'tcx> { } /// Description of a type-checked function parameter. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Param<'tcx> { /// The pattern that appears in the parameter list, or None for implicit parameters. pub pat: Option>>, @@ -118,7 +118,7 @@ pub enum LintLevel { Explicit(HirId), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Block { /// Whether the block itself has a label. Used by `label: {}` /// and `try` blocks. @@ -138,7 +138,7 @@ pub struct Block { type UserTy<'tcx> = Option>>; -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct AdtExpr<'tcx> { /// The ADT we're constructing. pub adt_def: AdtDef<'tcx>, @@ -155,7 +155,7 @@ pub struct AdtExpr<'tcx> { pub base: AdtExprBase<'tcx>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum AdtExprBase<'tcx> { /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`. None, @@ -168,7 +168,7 @@ pub enum AdtExprBase<'tcx> { DefaultFields(Box<[Ty<'tcx>]>), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct ClosureExpr<'tcx> { pub closure_id: LocalDefId, pub args: UpvarArgs<'tcx>, @@ -177,7 +177,7 @@ pub struct ClosureExpr<'tcx> { pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct InlineAsmExpr<'tcx> { pub asm_macro: AsmMacro, pub template: &'tcx [InlineAsmTemplatePiece], @@ -195,12 +195,12 @@ pub enum BlockSafety { ExplicitUnsafe(HirId), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum StmtKind<'tcx> { /// An expression with a trailing semicolon. Expr { @@ -240,11 +240,11 @@ pub enum StmtKind<'tcx> { }, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub struct LocalVarId(pub HirId); /// A THIR expression. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Expr<'tcx> { /// kind of expression pub kind: ExprKind<'tcx>, @@ -271,7 +271,7 @@ pub struct TempLifetime { pub backwards_incompatible: Option, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum ExprKind<'tcx> { /// `Scope`s are used to explicitly mark destruction scopes, /// and to track the `HirId` of the expressions within the scope. @@ -548,20 +548,20 @@ pub enum ExprKind<'tcx> { /// Represents the association of a field identifier and an expression. /// /// This is used in struct constructors. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct FieldExpr { pub name: FieldIdx, pub expr: ExprId, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct FruInfo<'tcx> { pub base: ExprId, pub field_types: Box<[Ty<'tcx>]>, } /// A `match` arm. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { pub pattern: Box>, pub guard: Option, @@ -579,7 +579,7 @@ pub enum LogicalOp { Or, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -616,13 +616,13 @@ pub enum InlineAsmOperand<'tcx> { }, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, pub pattern: Pat<'tcx>, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -729,7 +729,7 @@ impl<'tcx> Pat<'tcx> { } } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, /// Variance to use when relating the `user_ty` to the **type of the value being @@ -753,7 +753,7 @@ pub struct Ascription<'tcx> { pub variance: ty::Variance, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, From b5f0c82eba0bdc1d753dc5e0e62326769d7360d2 Mon Sep 17 00:00:00 2001 From: Niels Saurer Date: Thu, 27 Feb 2025 18:33:44 +0100 Subject: [PATCH 06/40] Add note to Thir struct about necessity of Clone derive --- compiler/rustc_middle/src/thir.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index fabee391ac678..72f31cec00826 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -49,6 +49,9 @@ macro_rules! thir_with_elements { } )* + // Note: Making `Thir` implement `Clone` is useful for external tools that need access to + // THIR bodies even after the `Steal` query result has been stolen. + // One such tool is https://github.com/rust-corpus/qrates/. /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). From 67cc82a704a38fcd574b0dc4373d939effed9496 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 15 Feb 2025 01:56:52 -0800 Subject: [PATCH 07/40] Inline VecDeque and BorrowedCursor methods All other methods in this file have #[inline] and these methods are very similar to those of &[u8] which are already inlined here. --- library/std/src/io/impls.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 8239b29884e8e..7885332cfde55 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -515,6 +515,7 @@ impl Read for VecDeque { Ok(n) } + #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let (front, back) = self.as_slices(); @@ -547,6 +548,7 @@ impl Read for VecDeque { Ok(()) } + #[inline] fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let len = cursor.capacity(); let (front, back) = self.as_slices(); @@ -646,6 +648,7 @@ impl Write for VecDeque { #[unstable(feature = "read_buf", issue = "78485")] impl<'a> io::Write for core::io::BorrowedCursor<'a> { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { let amt = cmp::min(buf.len(), self.capacity()); self.append(&buf[..amt]); From 41bdd2b74a8c380fb0fec1ad4d8ee21a11238a8b Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 15 Feb 2025 18:51:33 -0800 Subject: [PATCH 08/40] Override default Write methods for cursor-like types --- library/std/src/io/cursor.rs | 100 ++++++++++++++++++++++++++++++----- library/std/src/io/impls.rs | 57 +++++++++++++++++++- 2 files changed, 143 insertions(+), 14 deletions(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 08832bbc1e3d1..d7131e2fe92fd 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -439,6 +439,27 @@ fn slice_write_vectored( Ok(nwritten) } +#[inline] +fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } +} + +#[inline] +fn slice_write_all_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoSlice<'_>], +) -> io::Result<()> { + for buf in bufs { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) +} + /// Reserves the required space, and pads the vec with 0s if necessary. fn reserve_and_pad( pos_mut: &mut u64, @@ -481,9 +502,12 @@ fn reserve_and_pad( Ok(pos) } -/// Writes the slice to the vec without allocating -/// # Safety: vec must have buf.len() spare capacity -unsafe fn vec_write_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize +/// Writes the slice to the vec without allocating. +/// +/// # Safety +/// +/// `vec` must have `buf.len()` spare capacity. +unsafe fn vec_write_all_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize where A: Allocator, { @@ -492,7 +516,7 @@ where pos + buf.len() } -/// Resizing write implementation for [`Cursor`] +/// Resizing `write_all` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -501,7 +525,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result +fn vec_write_all(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result where A: Allocator, { @@ -512,7 +536,7 @@ where // Safety: we have ensured that the capacity is available // and that all bytes get written up to pos unsafe { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); if pos > vec.len() { vec.set_len(pos); } @@ -523,7 +547,7 @@ where Ok(buf_len) } -/// Resizing write_vectored implementation for [`Cursor`] +/// Resizing `write_all_vectored` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -532,7 +556,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write_vectored( +fn vec_write_all_vectored( pos_mut: &mut u64, vec: &mut Vec, bufs: &[IoSlice<'_>], @@ -550,7 +574,7 @@ where // and that all bytes get written up to the last pos unsafe { for buf in bufs { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); } if pos > vec.len() { vec.set_len(pos); @@ -579,6 +603,16 @@ impl Write for Cursor<&mut [u8]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -591,11 +625,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, self.inner, buf) + vec_write_all(&mut self.pos, self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, self.inner, bufs) + vec_write_all_vectored(&mut self.pos, self.inner, bufs) } #[inline] @@ -603,6 +637,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -615,11 +659,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, &mut self.inner, buf) + vec_write_all(&mut self.pos, &mut self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, &mut self.inner, bufs) + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs) } #[inline] @@ -627,6 +671,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, &mut self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -653,6 +707,16 @@ where true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -676,6 +740,16 @@ impl Write for Cursor<[u8; N]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 7885332cfde55..d0245f3d4984c 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -455,7 +455,17 @@ impl Write for &mut [u8] { #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) } + if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) } #[inline] @@ -495,6 +505,12 @@ impl Write for Vec { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -640,6 +656,12 @@ impl Write for VecDeque { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -655,6 +677,39 @@ impl<'a> io::Write for core::io::BorrowedCursor<'a> { Ok(amt) } + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + let n = self.write(buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) From b2bb7cc8ae45e8852e4b76fa10408a1eed626412 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Thu, 27 Feb 2025 19:06:06 -0800 Subject: [PATCH 09/40] Fix char count in Display for ByteStr --- library/core/src/bstr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs index 74e07f3d242cd..ae84fd8adb61c 100644 --- a/library/core/src/bstr.rs +++ b/library/core/src/bstr.rs @@ -151,7 +151,9 @@ impl fmt::Display for ByteStr { }; let nchars: usize = self .utf8_chunks() - .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 }) + .map(|chunk| { + chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } + }) .sum(); let padding = f.width().unwrap_or(0).saturating_sub(nchars); let fill = f.fill(); From 41dd80aeaa706c169df62bdf16033b61b914cb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 26 Feb 2025 14:29:19 +0100 Subject: [PATCH 10/40] add test to reproduce #137662 (using ty decl macro fragment in an attr) and fix it --- compiler/rustc_attr_parsing/src/parser.rs | 9 +++++++++ .../attributes/decl_macro_ty_in_attr_macro.rs | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/attributes/decl_macro_ty_in_attr_macro.rs diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index b6d66af4466e2..6c2448b751283 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -473,6 +473,15 @@ impl<'a> MetaItemListParserContext<'a> { { self.inside_delimiters.next(); return Some(MetaItemOrLitParser::Lit(lit)); + } else if let Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) = + self.inside_delimiters.peek() + { + self.inside_delimiters.next(); + return MetaItemListParserContext { + inside_delimiters: inner_tokens.iter().peekable(), + dcx: self.dcx, + } + .next(); } // or a path. diff --git a/tests/ui/attributes/decl_macro_ty_in_attr_macro.rs b/tests/ui/attributes/decl_macro_ty_in_attr_macro.rs new file mode 100644 index 0000000000000..e633c08be3ad2 --- /dev/null +++ b/tests/ui/attributes/decl_macro_ty_in_attr_macro.rs @@ -0,0 +1,20 @@ +// tests for #137662: using a ty or (or most other) fragment inside an attr macro wouldn't work +// because of a missing code path. With $repr: tt it did work. +//@ check-pass + +macro_rules! foo { + { + $repr:ty + } => { + #[repr($repr)] + pub enum Foo { + Bar = 0i32, + } + } +} + +foo! { + i32 +} + +fn main() {} From 50a37ca56c1f13fdfc0df789a92d0052e731e9ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2025 15:54:26 +0100 Subject: [PATCH 11/40] miri native-call support: all previously exposed provenance is accessible to the callee --- .../rustc_const_eval/src/interpret/memory.rs | 15 +++---- src/tools/miri/src/alloc_addresses/mod.rs | 25 +++++++++++- src/tools/miri/src/machine.rs | 10 +---- src/tools/miri/src/shims/native_lib.rs | 16 +++----- .../tests/native-lib/pass/ptr_write_access.rs | 40 +++++++++++++++++-- .../miri/tests/native-lib/ptr_write_access.c | 19 +++++++++ 6 files changed, 92 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 4f4b6785844dc..ce0b5a350e030 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -955,18 +955,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Handle the effect an FFI call might have on the state of allocations. /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all provenances as exposed + /// We set all reachable allocations as initialized, mark all reachable provenances as exposed /// and overwrite them with `Provenance::WILDCARD`. - pub fn prepare_for_native_call( - &mut self, - id: AllocId, - initial_prov: M::Provenance, - ) -> InterpResult<'tcx> { - // Expose provenance of the root allocation. - M::expose_provenance(self, initial_prov)?; - + /// + /// The allocations in `ids` are assumed to be already exposed. + pub fn prepare_for_native_call(&mut self, ids: Vec) -> InterpResult<'tcx> { let mut done = FxHashSet::default(); - let mut todo = vec![id]; + let mut todo = ids; while let Some(id) = todo.pop() { if !done.insert(id) { // We already saw this allocation before, don't process it again. diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index a4f2a117b181c..ff3a25e94bd5d 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -285,9 +285,19 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn expose_ptr(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let mut global_state = this.machine.alloc_addresses.borrow_mut(); + + let (alloc_id, tag) = match provenance { + Provenance::Concrete { alloc_id, tag } => (alloc_id, tag), + Provenance::Wildcard => { + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. + return interp_ok(()); + } + }; + // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode == ProvenanceMode::Strict { return interp_ok(()); @@ -422,6 +432,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let rel_offset = this.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); Some((alloc_id, Size::from_bytes(rel_offset))) } + + /// Prepare all exposed memory for a native call. + /// This overapproximates the modifications which external code might make to memory: + /// We set all reachable allocations as initialized, mark all reachable provenances as exposed + /// and overwrite them with `Provenance::WILDCARD`. + fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // We need to make a deep copy of this list, but it's fine; it also serves as scratch space + // for the search within `prepare_for_native_call`. + let exposed: Vec = + this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect(); + this.prepare_for_native_call(exposed) + } } impl<'tcx> MiriMachine<'tcx> { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 4ece8f7895dee..dbb092f67286a 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1291,18 +1291,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// Called on `ptr as usize` casts. /// (Actually computing the resulting `usize` doesn't need machine help, /// that's just `Scalar::try_to_int`.) + #[inline(always)] fn expose_provenance( ecx: &InterpCx<'tcx, Self>, provenance: Self::Provenance, ) -> InterpResult<'tcx> { - match provenance { - Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag), - Provenance::Wildcard => { - // No need to do anything for wildcard pointers as - // their provenances have already been previously exposed. - interp_ok(()) - } - } + ecx.expose_provenance(provenance) } /// Convert a pointer with provenance into an allocation-offset pair and extra provenance info. diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 8c9e1860f31d9..c6fcb0355eb80 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -160,16 +160,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let imm = this.read_immediate(arg)?; libffi_args.push(imm_to_carg(&imm, this)?); - // If we are passing a pointer, prepare the memory it points to. + // If we are passing a pointer, expose its provenance. Below, all exposed memory + // (previously exposed and new exposed) will then be properly prepared. if matches!(arg.layout.ty.kind(), ty::RawPtr(..)) { let ptr = imm.to_scalar().to_pointer(this)?; let Some(prov) = ptr.provenance else { - // Pointer without provenance may not access any memory. - continue; - }; - // We use `get_alloc_id` for its best-effort behaviour with Wildcard provenance. - let Some(alloc_id) = prov.get_alloc_id() else { - // Wildcard pointer, whatever it points to must be already exposed. + // Pointer without provenance may not access any memory anyway, skip. continue; }; // The first time this happens, print a warning. @@ -178,12 +174,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem); } - this.prepare_for_native_call(alloc_id, prov)?; + this.expose_provenance(prov)?; } } - // FIXME: In the future, we should also call `prepare_for_native_call` on all previously - // exposed allocations, since C may access any of them. + // Prepare all exposed memory. + this.prepare_exposed_for_native_call()?; // Convert them to `libffi::high::Arg` type. let libffi_args = libffi_args diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs index a92e63a4da6d8..bd4e0b23601f1 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs @@ -6,7 +6,7 @@ #![feature(box_as_ptr)] use std::mem::MaybeUninit; -use std::ptr::null; +use std::ptr; fn main() { test_increment_int(); @@ -20,6 +20,8 @@ fn main() { test_pass_dangling(); test_swap_ptr_triple_dangling(); test_return_ptr(); + test_pass_ptr_as_int(); + test_pass_ptr_via_previously_shared_mem(); } /// Test function that modifies an int. @@ -112,7 +114,7 @@ fn test_swap_ptr() { } let x = 61; - let (mut ptr0, mut ptr1) = (&raw const x, null()); + let (mut ptr0, mut ptr1) = (&raw const x, ptr::null()); unsafe { swap_ptr(&mut ptr0, &mut ptr1) }; assert_eq!(unsafe { *ptr1 }, x); @@ -131,7 +133,7 @@ fn test_swap_ptr_tuple() { } let x = 71; - let mut tuple = Tuple { ptr0: &raw const x, ptr1: null() }; + let mut tuple = Tuple { ptr0: &raw const x, ptr1: ptr::null() }; unsafe { swap_ptr_tuple(&mut tuple) } assert_eq!(unsafe { *tuple.ptr1 }, x); @@ -148,7 +150,7 @@ fn test_overwrite_dangling() { drop(b); unsafe { overwrite_ptr(&mut ptr) }; - assert_eq!(ptr, null()); + assert_eq!(ptr, ptr::null()); } /// Test function that passes a dangling pointer. @@ -200,3 +202,33 @@ fn test_return_ptr() { let ptr = unsafe { return_ptr(ptr) }; assert_eq!(unsafe { *ptr }, x); } + +/// Test casting a pointer to an integer and passing that to C. +fn test_pass_ptr_as_int() { + extern "C" { + fn pass_ptr_as_int(ptr: usize, set_to_val: i32); + } + + let mut m: MaybeUninit = MaybeUninit::uninit(); + unsafe { pass_ptr_as_int(m.as_mut_ptr() as usize, 42) }; + assert_eq!(unsafe { m.assume_init() }, 42); +} + +fn test_pass_ptr_via_previously_shared_mem() { + extern "C" { + fn set_shared_mem(ptr: *mut *mut i32); + fn init_ptr_stored_in_shared_mem(val: i32); + } + + let mut m: *mut i32 = ptr::null_mut(); + let ptr_to_m = &raw mut m; + unsafe { set_shared_mem(&raw mut m) }; + + let mut m2: MaybeUninit = MaybeUninit::uninit(); + // Store a pointer to m2 somewhere that C code can access it. + unsafe { ptr_to_m.write(m2.as_mut_ptr()) }; + // Have C code write there. + unsafe { init_ptr_stored_in_shared_mem(42) }; + // Ensure this memory is now considered initialized. + assert_eq!(unsafe { m2.assume_init() }, 42); +} diff --git a/src/tools/miri/tests/native-lib/ptr_write_access.c b/src/tools/miri/tests/native-lib/ptr_write_access.c index b54c5d86b210d..96fe413c0d8c0 100644 --- a/src/tools/miri/tests/native-lib/ptr_write_access.c +++ b/src/tools/miri/tests/native-lib/ptr_write_access.c @@ -1,4 +1,5 @@ #include +#include // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) @@ -88,3 +89,21 @@ EXPORT void swap_ptr_triple_dangling(Triple *t_ptr) { EXPORT const int *return_ptr(const int *ptr) { return ptr; } + +/* Test: test_pass_ptr_as_int */ + +EXPORT void pass_ptr_as_int(uintptr_t ptr, int set_to_val) { + *(int*)ptr = set_to_val; +} + +/* Test: test_pass_ptr_via_previously_shared_mem */ + +int** shared_place; + +EXPORT void set_shared_mem(int** ptr) { + shared_place = ptr; +} + +EXPORT void init_ptr_stored_in_shared_mem(int val) { + **shared_place = val; +} From 88f988cf139797edd56aea011998d5c9f07b5685 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2025 16:06:27 +0100 Subject: [PATCH 12/40] use fixed-width integer types in C code --- .../miri/tests/native-lib/ptr_read_access.c | 15 +++--- .../miri/tests/native-lib/ptr_write_access.c | 46 +++++++++---------- .../miri/tests/native-lib/scalar_arguments.c | 13 +++--- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 3b427d6033e3d..b89126d3d7c88 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -1,33 +1,34 @@ #include +#include // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) /* Test: test_access_pointer */ -EXPORT void print_pointer(const int *ptr) { +EXPORT void print_pointer(const int32_t *ptr) { printf("printing pointer dereference from C: %d\n", *ptr); } /* Test: test_access_simple */ typedef struct Simple { - int field; + int32_t field; } Simple; -EXPORT int access_simple(const Simple *s_ptr) { +EXPORT int32_t access_simple(const Simple *s_ptr) { return s_ptr->field; } /* Test: test_access_nested */ typedef struct Nested { - int value; + int32_t value; struct Nested *next; } Nested; // Returns the innermost/last value of a Nested pointer chain. -EXPORT int access_nested(const Nested *n_ptr) { +EXPORT int32_t access_nested(const Nested *n_ptr) { // Edge case: `n_ptr == NULL` (i.e. first Nested is None). if (!n_ptr) { return 0; } @@ -41,10 +42,10 @@ EXPORT int access_nested(const Nested *n_ptr) { /* Test: test_access_static */ typedef struct Static { - int value; + int32_t value; struct Static *recurse; } Static; -EXPORT int access_static(const Static *s_ptr) { +EXPORT int32_t access_static(const Static *s_ptr) { return s_ptr->recurse->recurse->value; } diff --git a/src/tools/miri/tests/native-lib/ptr_write_access.c b/src/tools/miri/tests/native-lib/ptr_write_access.c index 96fe413c0d8c0..fd8b005499c76 100644 --- a/src/tools/miri/tests/native-lib/ptr_write_access.c +++ b/src/tools/miri/tests/native-lib/ptr_write_access.c @@ -6,19 +6,19 @@ /* Test: test_increment_int */ -EXPORT void increment_int(int *ptr) { +EXPORT void increment_int(int32_t *ptr) { *ptr += 1; } /* Test: test_init_int */ -EXPORT void init_int(int *ptr, int val) { +EXPORT void init_int(int32_t *ptr, int32_t val) { *ptr = val; } /* Test: test_init_array */ -EXPORT void init_array(int *array, size_t len, int val) { +EXPORT void init_array(int32_t *array, size_t len, int32_t val) { for (size_t i = 0; i < len; i++) { array[i] = val; } @@ -27,28 +27,28 @@ EXPORT void init_array(int *array, size_t len, int val) { /* Test: test_init_static_inner */ typedef struct SyncPtr { - int *ptr; + int32_t *ptr; } SyncPtr; -EXPORT void init_static_inner(const SyncPtr *s_ptr, int val) { +EXPORT void init_static_inner(const SyncPtr *s_ptr, int32_t val) { *(s_ptr->ptr) = val; } /* Tests: test_exposed, test_pass_dangling */ -EXPORT void ignore_ptr(__attribute__((unused)) const int *ptr) { +EXPORT void ignore_ptr(__attribute__((unused)) const int32_t *ptr) { return; } /* Test: test_expose_int */ -EXPORT void expose_int(const int *int_ptr, const int **pptr) { +EXPORT void expose_int(const int32_t *int_ptr, const int32_t **pptr) { *pptr = int_ptr; } /* Test: test_swap_ptr */ -EXPORT void swap_ptr(const int **pptr0, const int **pptr1) { - const int *tmp = *pptr0; +EXPORT void swap_ptr(const int32_t **pptr0, const int32_t **pptr1) { + const int32_t *tmp = *pptr0; *pptr0 = *pptr1; *pptr1 = tmp; } @@ -56,54 +56,54 @@ EXPORT void swap_ptr(const int **pptr0, const int **pptr1) { /* Test: test_swap_ptr_tuple */ typedef struct Tuple { - int *ptr0; - int *ptr1; + int32_t *ptr0; + int32_t *ptr1; } Tuple; EXPORT void swap_ptr_tuple(Tuple *t_ptr) { - int *tmp = t_ptr->ptr0; + int32_t *tmp = t_ptr->ptr0; t_ptr->ptr0 = t_ptr->ptr1; t_ptr->ptr1 = tmp; } /* Test: test_overwrite_dangling */ -EXPORT void overwrite_ptr(const int **pptr) { +EXPORT void overwrite_ptr(const int32_t **pptr) { *pptr = NULL; } /* Test: test_swap_ptr_triple_dangling */ typedef struct Triple { - int *ptr0; - int *ptr1; - int *ptr2; + int32_t *ptr0; + int32_t *ptr1; + int32_t *ptr2; } Triple; EXPORT void swap_ptr_triple_dangling(Triple *t_ptr) { - int *tmp = t_ptr->ptr0; + int32_t *tmp = t_ptr->ptr0; t_ptr->ptr0 = t_ptr->ptr2; t_ptr->ptr2 = tmp; } -EXPORT const int *return_ptr(const int *ptr) { +EXPORT const int32_t *return_ptr(const int32_t *ptr) { return ptr; } /* Test: test_pass_ptr_as_int */ -EXPORT void pass_ptr_as_int(uintptr_t ptr, int set_to_val) { - *(int*)ptr = set_to_val; +EXPORT void pass_ptr_as_int(uintptr_t ptr, int32_t set_to_val) { + *(int32_t*)ptr = set_to_val; } /* Test: test_pass_ptr_via_previously_shared_mem */ -int** shared_place; +int32_t** shared_place; -EXPORT void set_shared_mem(int** ptr) { +EXPORT void set_shared_mem(int32_t** ptr) { shared_place = ptr; } -EXPORT void init_ptr_stored_in_shared_mem(int val) { +EXPORT void init_ptr_stored_in_shared_mem(int32_t val) { **shared_place = val; } diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 6da730a498724..acccf06f3df2b 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -1,9 +1,10 @@ #include +#include // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) -EXPORT int add_one_int(int x) { +EXPORT int32_t add_one_int(int32_t x) { return 2 + x; } @@ -13,23 +14,23 @@ EXPORT void printer(void) { // function with many arguments, to test functionality when some args are stored // on the stack -EXPORT int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { +EXPORT int32_t test_stack_spill(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f, int32_t g, int32_t h, int32_t i, int32_t j, int32_t k, int32_t l) { return a+b+c+d+e+f+g+h+i+j+k+l; } -EXPORT unsigned int get_unsigned_int(void) { +EXPORT uint32_t get_unsigned_int(void) { return -10; } -EXPORT short add_int16(short x) { +EXPORT short add_int16(int16_t x) { return x + 3; } -EXPORT long add_short_to_long(short x, long y) { +EXPORT long add_short_to_long(int16_t x, int64_t y) { return x + y; } // To test that functions not marked with EXPORT cannot be called by Miri. -int not_exported(void) { +int32_t not_exported(void) { return 0; } From 476b0980f22f4a4de2102f2994da39600fc4546d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2025 16:30:59 +0100 Subject: [PATCH 13/40] adjust Layout debug printing to match the internal field names --- compiler/rustc_abi/src/lib.rs | 2 +- tests/ui/abi/c-zst.aarch64-darwin.stderr | 4 +- tests/ui/abi/c-zst.powerpc-linux.stderr | 4 +- tests/ui/abi/c-zst.s390x-linux.stderr | 4 +- tests/ui/abi/c-zst.sparc64-linux.stderr | 4 +- tests/ui/abi/c-zst.x86_64-linux.stderr | 4 +- .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 4 +- tests/ui/abi/debug.stderr | 48 +++++++++---------- tests/ui/abi/sysv64-zst.stderr | 4 +- tests/ui/layout/debug.stderr | 36 +++++++------- tests/ui/layout/hexagon-enum.stderr | 20 ++++---- ...-scalarpair-payload-might-be-uninit.stderr | 34 ++++++------- .../issue-96185-overaligned-enum.stderr | 12 ++--- tests/ui/layout/thumb-enum.stderr | 20 ++++---- .../layout/zero-sized-array-enum-niche.stderr | 26 +++++----- ...-variants.aarch64-unknown-linux-gnu.stderr | 16 +++---- ...-c-dead-variants.armebv7r-none-eabi.stderr | 16 +++---- ...-dead-variants.i686-pc-windows-msvc.stderr | 16 +++---- ...d-variants.x86_64-unknown-linux-gnu.stderr | 16 +++---- tests/ui/repr/repr-c-int-dead-variants.stderr | 16 +++---- .../type/pattern_types/range_patterns.stderr | 18 +++---- 21 files changed, 162 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 81e4e255f3799..b91dedfe2005f 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1812,7 +1812,7 @@ where f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", backend_repr) + .field("backend_repr", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) .field("uninhabited", uninhabited) diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 57cc48aa9cf47..48fa2bf29bc40 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -38,7 +38,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index 6738017673003..bfdf94c99007c 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -49,7 +49,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index 6738017673003..bfdf94c99007c 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -49,7 +49,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index 6738017673003..bfdf94c99007c 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -49,7 +49,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 57cc48aa9cf47..48fa2bf29bc40 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -38,7 +38,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index 6738017673003..bfdf94c99007c 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -49,7 +49,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 5f73ff7d6bd58..2239ba0e5880a 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(test) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -48,7 +48,7 @@ error: fn_abi_of(test) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -107,7 +107,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -155,7 +155,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -205,7 +205,7 @@ error: fn_abi_of(test_generic) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Pointer( AddressSpace( @@ -245,7 +245,7 @@ error: fn_abi_of(test_generic) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -292,7 +292,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -331,7 +331,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -366,7 +366,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -405,7 +405,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -446,7 +446,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Array { @@ -486,7 +486,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -521,7 +521,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Array { @@ -561,7 +561,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -602,7 +602,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Float( F32, @@ -640,7 +640,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -675,7 +675,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -714,7 +714,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -755,7 +755,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -794,7 +794,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -829,7 +829,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -868,7 +868,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -923,7 +923,7 @@ error: fn_abi_of(assoc_test) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Pointer( AddressSpace( @@ -975,7 +975,7 @@ error: fn_abi_of(assoc_test) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index ec85030c10686..59d7b00441790 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -38,7 +38,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 07cad7766920f..80b35ff6ad49e 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -10,7 +10,7 @@ error: layout_of(E) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -49,7 +49,7 @@ error: layout_of(E) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -71,7 +71,7 @@ error: layout_of(E) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -112,7 +112,7 @@ error: layout_of(S) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -160,7 +160,7 @@ error: layout_of(U) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -186,7 +186,7 @@ error: layout_of(Result) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -238,7 +238,7 @@ error: layout_of(Result) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -277,7 +277,7 @@ error: layout_of(Result) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -327,7 +327,7 @@ error: layout_of(i32) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -357,7 +357,7 @@ error: layout_of(V) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -383,7 +383,7 @@ error: layout_of(W) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -409,7 +409,7 @@ error: layout_of(Y) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -435,7 +435,7 @@ error: layout_of(P1) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -461,7 +461,7 @@ error: layout_of(P2) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -487,7 +487,7 @@ error: layout_of(P3) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -513,7 +513,7 @@ error: layout_of(P4) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Union( @@ -539,7 +539,7 @@ error: layout_of(P5) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Union { value: Int( I8, @@ -570,7 +570,7 @@ error: layout_of(MaybeUninit) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Union { value: Int( I8, diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index 90c06ba1f834e..1cd4efbcdad38 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -4,7 +4,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -49,7 +49,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -82,7 +82,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -127,7 +127,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -160,7 +160,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(2 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I16, @@ -205,7 +205,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(2 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -238,7 +238,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -283,7 +283,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -316,7 +316,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -361,7 +361,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 3bdb9c5c143e4..ef7f0cd2d1c34 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -4,7 +4,7 @@ error: layout_of(MissingPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -55,7 +55,7 @@ error: layout_of(MissingPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -93,7 +93,7 @@ error: layout_of(MissingPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -126,7 +126,7 @@ error: layout_of(CommonPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -178,7 +178,7 @@ error: layout_of(CommonPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -217,7 +217,7 @@ error: layout_of(CommonPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -267,7 +267,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -318,7 +318,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -356,7 +356,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -405,7 +405,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -460,7 +460,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -510,7 +510,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -532,7 +532,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -565,7 +565,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -620,7 +620,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -670,7 +670,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -692,7 +692,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index 1d4e443644826..a9081afc50944 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -4,7 +4,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -43,7 +43,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -67,7 +67,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -104,7 +104,7 @@ error: layout_of(Aligned2) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -149,7 +149,7 @@ error: layout_of(Aligned2) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -173,7 +173,7 @@ error: layout_of(Aligned2) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 0c34331856474..c1defe720db9c 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -4,7 +4,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -49,7 +49,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -82,7 +82,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -127,7 +127,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -160,7 +160,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I16, @@ -205,7 +205,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -238,7 +238,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -283,7 +283,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -316,7 +316,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -361,7 +361,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 33d2eede22090..1ba184bdacefb 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -4,7 +4,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -43,7 +43,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -115,7 +115,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -154,7 +154,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(2 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -180,7 +180,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -206,7 +206,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -252,7 +252,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -291,7 +291,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -317,7 +317,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -363,7 +363,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -406,7 +406,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -432,7 +432,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index 204db30786ee3..5ae5aeb7d2c3b 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -4,7 +4,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -49,7 +49,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -92,7 +92,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -143,7 +143,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -181,7 +181,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -230,7 +230,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -269,7 +269,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -299,7 +299,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 1fab00bf50c49..a325cb8d71ffe 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -4,7 +4,7 @@ error: layout_of(Univariant) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -49,7 +49,7 @@ error: layout_of(Univariant) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -92,7 +92,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -143,7 +143,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -181,7 +181,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -230,7 +230,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -269,7 +269,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -299,7 +299,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index 204db30786ee3..5ae5aeb7d2c3b 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -4,7 +4,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -49,7 +49,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -92,7 +92,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -143,7 +143,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -181,7 +181,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -230,7 +230,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -269,7 +269,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -299,7 +299,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index 204db30786ee3..5ae5aeb7d2c3b 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -4,7 +4,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -49,7 +49,7 @@ error: layout_of(Univariant) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -92,7 +92,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -143,7 +143,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -181,7 +181,7 @@ error: layout_of(TwoVariants) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I32, @@ -230,7 +230,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -269,7 +269,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -299,7 +299,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index f852212deb908..f63574182c25f 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -4,7 +4,7 @@ error: layout_of(UnivariantU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -49,7 +49,7 @@ error: layout_of(UnivariantU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I8, @@ -92,7 +92,7 @@ error: layout_of(TwoVariantsU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -143,7 +143,7 @@ error: layout_of(TwoVariantsU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -181,7 +181,7 @@ error: layout_of(TwoVariantsU8) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: ScalarPair( + backend_repr: ScalarPair( Initialized { value: Int( I8, @@ -230,7 +230,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -269,7 +269,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -299,7 +299,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index 690592ba0b8da..7eda50fd12116 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -4,7 +4,7 @@ error: layout_of(NonZero) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -50,7 +50,7 @@ error: layout_of((u32) is 1..=) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -89,7 +89,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -129,7 +129,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -151,7 +151,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -203,7 +203,7 @@ error: layout_of(Option>) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -243,7 +243,7 @@ error: layout_of(Option>) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Memory { + backend_repr: Memory { sized: true, }, fields: Arbitrary { @@ -265,7 +265,7 @@ error: layout_of(Option>) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, @@ -317,7 +317,7 @@ error: layout_of(NonZeroU32New) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Scalar( + backend_repr: Scalar( Initialized { value: Int( I32, From 91034adf30b3055e489d59f4483ed5def9cc9f19 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Fri, 28 Feb 2025 16:32:06 +0000 Subject: [PATCH 14/40] Do not require that unsafe fields lack drop glue Instead, we adopt the position that introducing an `unsafe` field itself carries a safety invariant: that if you assign an invariant to that field weaker than what the field's destructor requires, you must ensure that field is in a droppable state in your destructor. See: - https://github.com/rust-lang/rfcs/pull/3458#discussion_r1971676100 - https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/unsafe.20fields.20RFC/near/502113897 --- compiler/rustc_hir_analysis/messages.ftl | 7 ---- .../rustc_hir_analysis/src/check/check.rs | 32 ------------------- compiler/rustc_hir_analysis/src/errors.rs | 23 ------------- library/core/src/marker.rs | 4 +-- tests/ui/unsafe-fields/unsafe-fields.rs | 2 +- tests/ui/unsafe-fields/unsafe-fields.stderr | 17 ++-------- 6 files changed, 5 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 3f75cce009225..fe2254faf61e8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -278,13 +278,6 @@ hir_analysis_invalid_union_field = hir_analysis_invalid_union_field_sugg = wrap the field type in `ManuallyDrop<...>` -hir_analysis_invalid_unsafe_field = - field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe - .note = unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` - -hir_analysis_invalid_unsafe_field_sugg = - wrap the field type in `ManuallyDrop<...>` - hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl .label = const parameter declared here diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f2331f3fd8e13..25dc6b7954b21 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -70,7 +70,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_packed(tcx, span, def); - check_unsafe_fields(tcx, def_id); } fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -144,36 +143,6 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b true } -/// Check that the unsafe fields do not need dropping. -fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { - let span = tcx.def_span(item_def_id); - let def = tcx.adt_def(item_def_id); - - let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); - let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); - - for field in def.all_fields() { - if !field.safety.is_unsafe() { - continue; - } - - if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { - let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else { - unreachable!("field has to correspond to hir field") - }; - let ty_span = field.ty.span; - tcx.dcx().emit_err(errors::InvalidUnsafeField { - field_span: field.span, - sugg: errors::InvalidUnsafeFieldSuggestion { - lo: ty_span.shrink_to_lo(), - hi: ty_span.shrink_to_hi(), - }, - note: (), - }); - } - } -} - /// Check that a `static` is inhabited. fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Make sure statics are inhabited. @@ -1517,7 +1486,6 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { detect_discriminant_duplicate(tcx, def); check_transparent(tcx, def); - check_unsafe_fields(tcx, def_id); } /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 852533ff5c954..d000314974ce2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -710,17 +710,6 @@ pub(crate) struct InvalidUnionField { pub note: (), } -#[derive(Diagnostic)] -#[diag(hir_analysis_invalid_unsafe_field, code = E0740)] -pub(crate) struct InvalidUnsafeField { - #[primary_span] - pub field_span: Span, - #[subdiagnostic] - pub sugg: InvalidUnsafeFieldSuggestion, - #[note] - pub note: (), -} - #[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_on_non_rpitit)] pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> { @@ -742,18 +731,6 @@ pub(crate) struct InvalidUnionFieldSuggestion { pub hi: Span, } -#[derive(Subdiagnostic)] -#[multipart_suggestion( - hir_analysis_invalid_unsafe_field_sugg, - applicability = "machine-applicable" -)] -pub(crate) struct InvalidUnsafeFieldSuggestion { - #[suggestion_part(code = "std::mem::ManuallyDrop<")] - pub lo: Span, - #[suggestion_part(code = ">")] - pub hi: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_equality_bound)] pub(crate) struct ReturnTypeNotationEqualityBound { diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index b0571bf7247af..e2dd813981d04 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -453,8 +453,8 @@ impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] impl Copy for &T {} -/// Marker trait for the types that are allowed in union fields, unsafe fields, -/// and unsafe binder types. +/// Marker trait for the types that are allowed in union fields and unsafe +/// binder types. /// /// Implemented for: /// * `&T`, `&mut T` for all `T`, diff --git a/tests/ui/unsafe-fields/unsafe-fields.rs b/tests/ui/unsafe-fields/unsafe-fields.rs index 637471582d7e4..cb86479bb20d3 100644 --- a/tests/ui/unsafe-fields/unsafe-fields.rs +++ b/tests/ui/unsafe-fields/unsafe-fields.rs @@ -17,7 +17,7 @@ fn f(a: A) { } struct WithInvalidUnsafeField { - unsafe unsafe_noncopy_field: Vec, //~ ERROR + unsafe unsafe_noncopy_field: Vec, } struct WithManuallyDropUnsafeField { diff --git a/tests/ui/unsafe-fields/unsafe-fields.stderr b/tests/ui/unsafe-fields/unsafe-fields.stderr index a1c5d2b44cdf1..d0e2dc16a13d5 100644 --- a/tests/ui/unsafe-fields/unsafe-fields.stderr +++ b/tests/ui/unsafe-fields/unsafe-fields.stderr @@ -1,15 +1,3 @@ -error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe - --> $DIR/unsafe-fields.rs:20:5 - | -LL | unsafe unsafe_noncopy_field: Vec, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` -help: wrap the field type in `ManuallyDrop<...>` - | -LL | unsafe unsafe_noncopy_field: std::mem::ManuallyDrop>, - | +++++++++++++++++++++++ + - error[E0133]: use of unsafe field is unsafe and requires unsafe block --> $DIR/unsafe-fields.rs:15:30 | @@ -69,7 +57,6 @@ LL | &raw const self.unsafe_field | = note: unsafe fields may carry library invariants -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0133, E0740. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0133`. From b1196717fcba13d8ff73ec06c3d8c5bee3b74ec9 Mon Sep 17 00:00:00 2001 From: Will Woods Date: Fri, 28 Feb 2025 17:30:53 -0800 Subject: [PATCH 15/40] Tweak BufReader::peek() doctest to expose bug in Buffer::read_more() This patch makes BufReader::peek()'s doctest call read_more() to refill the buffer before the inner reader hits EOF. This exposes a bug in read_more() that causes an out-of-bounds slice access and segfault. --- library/std/src/io/buffered/bufreader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 8b46738ab8aee..697fb5974a3dd 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -118,16 +118,16 @@ impl BufReader { /// #![feature(bufreader_peek)] /// use std::io::{Read, BufReader}; /// - /// let mut bytes = &b"oh, hello"[..]; + /// let mut bytes = &b"oh, hello there"[..]; /// let mut rdr = BufReader::with_capacity(6, &mut bytes); /// assert_eq!(rdr.peek(2).unwrap(), b"oh"); /// let mut buf = [0; 4]; /// rdr.read(&mut buf[..]).unwrap(); /// assert_eq!(&buf, b"oh, "); - /// assert_eq!(rdr.peek(2).unwrap(), b"he"); + /// assert_eq!(rdr.peek(5).unwrap(), b"hello"); /// let mut s = String::new(); /// rdr.read_to_string(&mut s).unwrap(); - /// assert_eq!(&s, "hello"); + /// assert_eq!(&s, "hello there"); /// assert_eq!(rdr.peek(1).unwrap().len(), 0); /// ``` #[unstable(feature = "bufreader_peek", issue = "128405")] From 6d07144613ffb54e6856bd5543acfe5e12eb3447 Mon Sep 17 00:00:00 2001 From: Will Woods Date: Fri, 28 Feb 2025 17:36:19 -0800 Subject: [PATCH 16/40] Fix logic error in Buffer::read_more() Buffer::read_more() is supposed to refill the buffer without discarding its contents, which are in the range `pos .. filled`. It mistakenly borrows the range `pos ..`, fills that, and then increments `filled` by the amount read. This overwrites the buffer's existing contents and sets `filled` to a too-large value that either exposes uninitialized bytes or walks off the end of the buffer entirely. This patch makes it correctly fill only the unfilled portion of the buffer, which should maintain all the type invariants and fix the test failure introduced in commit b1196717fcb. --- library/std/src/io/buffered/bufreader/buffer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 5251cc302cb49..9fd2472ebdfdb 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -109,8 +109,8 @@ impl Buffer { /// Read more bytes into the buffer without discarding any of its contents pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { - let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]); - let old_init = self.initialized - self.pos; + let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); + let old_init = self.initialized - self.filled; unsafe { buf.set_init(old_init); } From adff091b3e144c294981e62ba3f5cb2e16995a10 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Feb 2025 20:11:05 +0000 Subject: [PATCH 17/40] Check dyn flavor before registering upcast goal on wide pointer cast in MIR typeck --- compiler/rustc_borrowck/src/type_check/mod.rs | 4 ++-- .../traits/trait-upcasting/dyn-to-dyn-star.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/trait-upcasting/dyn-to-dyn-star.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6d05696e146f1..480d90932b99a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2120,8 +2120,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // // Note that other checks (such as denying `dyn Send` -> `dyn // Debug`) are in `rustc_hir_typeck`. - if let ty::Dynamic(src_tty, _src_lt, _) = *src_tail.kind() - && let ty::Dynamic(dst_tty, dst_lt, _) = *dst_tail.kind() + if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind() + && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind() && src_tty.principal().is_some() && dst_tty.principal().is_some() { diff --git a/tests/ui/traits/trait-upcasting/dyn-to-dyn-star.rs b/tests/ui/traits/trait-upcasting/dyn-to-dyn-star.rs new file mode 100644 index 0000000000000..5936c93efad31 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/dyn-to-dyn-star.rs @@ -0,0 +1,19 @@ +// While somewhat nonsensical, this is a cast from a wide pointer to a thin pointer. +// Thus, we don't need to check an unsize goal here; there isn't any vtable casting +// happening at all. + +// Regression test for . + +//@ check-pass + +#![allow(incomplete_features)] +#![feature(dyn_star)] + +trait Foo {} +trait Bar {} + +fn cast(x: *const dyn Foo) { + x as *const dyn* Bar; +} + +fn main() {} From e213f4beeabbb2604565a8e9324f66c5c72780c6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 3 Mar 2025 04:09:43 +0000 Subject: [PATCH 18/40] Improve error message for AsyncFn trait failure for RPIT --- .../traits/fulfillment_errors.rs | 115 ++++++++++-------- .../src/error_reporting/traits/suggestions.rs | 5 +- .../src/traits/select/confirmation.rs | 4 +- .../async-closures/kind-due-to-rpit.rs | 14 +++ .../async-closures/kind-due-to-rpit.stderr | 17 +++ 5 files changed, 101 insertions(+), 54 deletions(-) create mode 100644 tests/ui/async-await/async-closures/kind-due-to-rpit.rs create mode 100644 tests/ui/async-await/async-closures/kind-due-to-rpit.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d270b4cf96ba8..389e8e7994dcc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -829,7 +829,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = *typeck_results.node_type(arg_hir_id).kind() { - // Otherwise, extract the closure kind from the obligation. + // Otherwise, extract the closure kind from the obligation, + // but only if we actually have an argument to deduce the + // closure type from... let mut err = self.report_closure_error( &obligation, closure_def_id, @@ -844,63 +846,72 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let self_ty = trait_pred.self_ty().skip_binder(); - if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { - let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { - ty::Closure(def_id, args) => { - (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) - } - ty::CoroutineClosure(def_id, args) => ( - def_id, - args.as_coroutine_closure() - .coroutine_closure_sig() - .map_bound(|sig| sig.tupled_inputs_ty), - Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), - ), - _ => return None, + let (expected_kind, trait_prefix) = + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { + (expected_kind, "") + } else if let Some(expected_kind) = + self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id()) + { + (expected_kind, "Async") + } else { + return None; }; - let expected_args = - trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1)); - - // Verify that the arguments are compatible. If the signature is - // mismatched, then we have a totally different error to report. - if self.enter_forall(found_args, |found_args| { - self.enter_forall(expected_args, |expected_args| { - !self.can_eq(obligation.param_env, expected_args, found_args) - }) - }) { - return None; + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; - if let Some(found_kind) = self.closure_kind(self_ty) - && !found_kind.extends(expected_kind) - { - let mut err = self.report_closure_error( - &obligation, - closure_def_id, - found_kind, - expected_kind, - "", - ); - self.note_obligation_cause(&mut err, &obligation); - return Some(err.emit()); - } + let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1)); - // If the closure has captures, then perhaps the reason that the trait - // is unimplemented is because async closures don't implement `Fn`/`FnMut` - // if they have captures. - if let Some(by_ref_captures) = by_ref_captures - && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() - && !sig_tys.skip_binder().output().is_unit() - { - let mut err = self.dcx().create_err(AsyncClosureNotFn { - span: self.tcx.def_span(closure_def_id), - kind: expected_kind.as_str(), - }); - self.note_obligation_cause(&mut err, &obligation); - return Some(err.emit()); - } + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_eq(obligation.param_env, expected_args, found_args) + }) + }) { + return None; } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + trait_prefix, + ); + self.note_obligation_cause(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() + && !sig_tys.skip_binder().output().is_unit() + { + let mut err = self.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + return Some(err.emit()); + } + None } 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 b85c18c53121f..bbf46fff71b8b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3191,7 +3191,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false }; - if !is_upvar_tys_infer_tuple { + let is_builtin_async_fn_trait = + tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some(); + + if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait { let ty_str = tcx.short_string(ty, err.long_ty_path()); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a58317dd56d24..4ed27e406d203 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -984,8 +984,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(SelectionError::Unimplemented); } } else { - nested.push(obligation.with( + nested.push(Obligation::new( self.tcx(), + obligation.derived_cause(ObligationCauseCode::BuiltinDerived), + obligation.param_env, ty::TraitRef::new( self.tcx(), self.tcx().require_lang_item( diff --git a/tests/ui/async-await/async-closures/kind-due-to-rpit.rs b/tests/ui/async-await/async-closures/kind-due-to-rpit.rs new file mode 100644 index 0000000000000..ad19d93b93a3c --- /dev/null +++ b/tests/ui/async-await/async-closures/kind-due-to-rpit.rs @@ -0,0 +1,14 @@ +//@ edition: 2024 + +// Make sure the error message is understandable when an `AsyncFn` goal is not satisfied +// (due to closure kind), and that goal originates from an RPIT. + +fn repro(foo: impl Into) -> impl AsyncFn() { + let inner_fn = async move || { + //~^ ERROR expected a closure that implements the `AsyncFn` trait + let _ = foo.into(); + }; + inner_fn +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/kind-due-to-rpit.stderr b/tests/ui/async-await/async-closures/kind-due-to-rpit.stderr new file mode 100644 index 0000000000000..982cc50e14f97 --- /dev/null +++ b/tests/ui/async-await/async-closures/kind-due-to-rpit.stderr @@ -0,0 +1,17 @@ +error[E0525]: expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnOnce` + --> $DIR/kind-due-to-rpit.rs:7:20 + | +LL | fn repro(foo: impl Into) -> impl AsyncFn() { + | -------------- the requirement to implement `AsyncFn` derives from here +LL | let inner_fn = async move || { + | ^^^^^^^^^^^^^ this closure implements `AsyncFnOnce`, not `AsyncFn` +LL | +LL | let _ = foo.into(); + | --- closure is `AsyncFnOnce` because it moves the variable `foo` out of its environment +LL | }; +LL | inner_fn + | -------- return type was inferred to be `{async closure@$DIR/kind-due-to-rpit.rs:7:20: 7:33}` here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0525`. From 0aacfe9d91d5001872bb482ea6973827cad20220 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Mar 2025 08:15:03 +0100 Subject: [PATCH 19/40] interpret/provenance_map: consistently use range_is_empty --- .../src/mir/interpret/allocation.rs | 2 +- .../interpret/allocation/provenance_map.rs | 42 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 95bc9b71fe0ad..e940e29522045 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -470,7 +470,7 @@ impl Allocation // Find the provenance. let (offset, _prov) = self .provenance - .range_get_ptrs(range, cx) + .range_ptrs_get(range, cx) .first() .copied() .expect("there must be provenance somewhere here"); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 82fb5f33b4c81..c9525df1f7940 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -67,7 +67,7 @@ impl ProvenanceMap { } impl ProvenanceMap { - fn adjusted_range(range: AllocRange, cx: &impl HasDataLayout) -> Range { + fn adjusted_range_ptrs(range: AllocRange, cx: &impl HasDataLayout) -> Range { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let adjusted_start = Size::from_bytes( @@ -79,26 +79,21 @@ impl ProvenanceMap { /// Returns all ptr-sized provenance in the given range. /// If the range has length 0, returns provenance that crosses the edge between `start-1` and /// `start`. - pub(super) fn range_get_ptrs( + pub(super) fn range_ptrs_get( &self, range: AllocRange, cx: &impl HasDataLayout, ) -> &[(Size, Prov)] { - self.ptrs.range(Self::adjusted_range(range, cx)) + self.ptrs.range(Self::adjusted_range_ptrs(range, cx)) } - /// `pm.range_get_ptrs_is_empty(r, cx)` == `pm.range_get_ptrs(r, cx).is_empty()`, but is - /// faster. - pub(super) fn range_get_ptrs_is_empty( - &self, - range: AllocRange, - cx: &impl HasDataLayout, - ) -> bool { - self.ptrs.range_is_empty(Self::adjusted_range(range, cx)) + /// `pm.range_ptrs_is_empty(r, cx)` == `pm.range_ptrs_get(r, cx).is_empty()`, but is faster. + pub(super) fn range_ptrs_is_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { + self.ptrs.range_is_empty(Self::adjusted_range_ptrs(range, cx)) } /// Returns all byte-wise provenance in the given range. - fn range_get_bytes(&self, range: AllocRange) -> &[(Size, Prov)] { + fn range_bytes_get(&self, range: AllocRange) -> &[(Size, Prov)] { if let Some(bytes) = self.bytes.as_ref() { bytes.range(range.start..range.end()) } else { @@ -106,9 +101,14 @@ impl ProvenanceMap { } } + /// Same as `range_bytes_get(range).is_empty()`, but faster. + fn range_bytes_is_empty(&self, range: AllocRange) -> bool { + self.bytes.as_ref().is_none_or(|bytes| bytes.range_is_empty(range.start..range.end())) + } + /// Get the provenance of a single byte. pub fn get(&self, offset: Size, cx: &impl HasDataLayout) -> Option { - let prov = self.range_get_ptrs(alloc_range(offset, Size::from_bytes(1)), cx); + let prov = self.range_ptrs_get(alloc_range(offset, Size::from_bytes(1)), cx); debug_assert!(prov.len() <= 1); if let Some(entry) = prov.first() { // If it overlaps with this byte, it is on this byte. @@ -132,7 +132,7 @@ impl ProvenanceMap { /// limit access to provenance outside of the `Allocation` abstraction. /// pub fn range_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { - self.range_get_ptrs_is_empty(range, cx) && self.range_get_bytes(range).is_empty() + self.range_ptrs_is_empty(range, cx) && self.range_bytes_is_empty(range) } /// Yields all the provenances stored in this map. @@ -164,14 +164,14 @@ impl ProvenanceMap { // provenance that overlaps with the given range. let (first, last) = { // Find all provenance overlapping the given range. - if self.range_get_ptrs_is_empty(range, cx) { + if self.range_ptrs_is_empty(range, cx) { // No provenance in this range, we are done. This is the common case. return Ok(()); } // This redoes some of the work of `range_get_ptrs_is_empty`, but this path is much // colder than the early return above, so it's worth it. - let provenance = self.range_get_ptrs(range, cx); + let provenance = self.range_ptrs_get(range, cx); ( provenance.first().unwrap().0, provenance.last().unwrap().0 + cx.data_layout().pointer_size, @@ -284,8 +284,8 @@ impl ProvenanceMap { // This includes the existing bytewise provenance in the range, and ptr provenance // that overlaps with the begin/end of the range. let mut dest_bytes_box = None; - let begin_overlap = self.range_get_ptrs(alloc_range(src.start, Size::ZERO), cx).first(); - let end_overlap = self.range_get_ptrs(alloc_range(src.end(), Size::ZERO), cx).first(); + let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first(); + let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first(); if !Prov::OFFSET_IS_ADDR { // There can't be any bytewise provenance, and we cannot split up the begin/end overlap. if let Some(entry) = begin_overlap { @@ -308,10 +308,10 @@ impl ProvenanceMap { } else { trace!("no start overlapping entry"); } + // Then the main part, bytewise provenance from `self.bytes`. - if let Some(all_bytes) = self.bytes.as_ref() { - bytes.extend(all_bytes.range(src.start..src.end())); - } + bytes.extend(self.range_bytes_get(src)); + // And finally possibly parts of a pointer at the end. if let Some(entry) = end_overlap { trace!("end overlapping entry: {entry:?}"); From 133705c402941c0825fe658a932289847478cf9f Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 27 Feb 2025 20:54:26 +0800 Subject: [PATCH 20/40] [rustdoc] hide item that is not marked as doc(inline) and whose src is doc(hidden) Signed-off-by: xizheyin --- src/librustdoc/passes/strip_hidden.rs | 22 +++++++++++++++++-- tests/rustdoc/doc-hidden-reexports-109449.rs | 18 +++++++-------- tests/rustdoc/doc-hidden-source.rs | 16 ++++++++++++++ tests/rustdoc/inline_cross/inline_hidden.rs | 4 ++-- tests/rustdoc/reexport-attr-merge.rs | 4 ++-- .../reexport-doc-hidden-inside-private.rs | 4 ++-- tests/rustdoc/reexport-doc-hidden.rs | 4 ++-- tests/rustdoc/reexport-hidden-macro.rs | 2 +- tests/rustdoc/reexport-of-doc-hidden.rs | 12 +++++----- 9 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 tests/rustdoc/doc-hidden-source.rs diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index a71bb62e56c74..bcdca862862d4 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -7,9 +7,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; use tracing::debug; -use crate::clean; use crate::clean::utils::inherits_doc_hidden; -use crate::clean::{Item, ItemIdSet}; +use crate::clean::{self, Item, ItemIdSet, reexport_chain}; use crate::core::DocContext; use crate::fold::{DocFolder, strip_item}; use crate::passes::{ImplStripper, Pass}; @@ -89,6 +88,25 @@ impl Stripper<'_, '_> { impl DocFolder for Stripper<'_, '_> { fn fold_item(&mut self, i: Item) -> Option { let has_doc_hidden = i.is_doc_hidden(); + + if let clean::ImportItem(clean::Import { source, .. }) = &i.kind + && let Some(source_did) = source.did + && let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) + { + let reexports = reexport_chain(self.tcx, import_def_id, source_did); + + // Check if any reexport in the chain has a hidden source + let has_hidden_source = reexports + .iter() + .filter_map(|reexport| reexport.id()) + .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did)) + || self.tcx.is_doc_hidden(source_did); + + if has_hidden_source { + return None; + } + } + let is_impl_or_exported_macro = match i.kind { clean::ImplItem(..) => true, // If the macro has the `#[macro_export]` attribute, it means it's accessible at the diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/doc-hidden-reexports-109449.rs index 8f195544120af..78b9214300a95 100644 --- a/tests/rustdoc/doc-hidden-reexports-109449.rs +++ b/tests/rustdoc/doc-hidden-reexports-109449.rs @@ -26,21 +26,21 @@ pub mod single_reexport { //@ has 'foo/single_reexport/index.html' // First we check that we have 4 type aliases. - //@ count - '//*[@id="main-content"]/*[@class="item-table reexports"]//code' 4 + //@ count - '//*[@id="main-content"]/*[@class="item-table reexports"]//code' 0 // Then we check that we have the correct link for each re-export. //@ !has - '//*[@href="struct.Foo.html"]' 'Foo' - //@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' + //@ !has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' pub use crate::private_module::Public as Foo; //@ !has - '//*[@href="type.Foo2.html"]' 'Foo2' - //@ has - '//*[@id="reexport.Foo2"]/code' 'pub use crate::private_module::Bar as Foo2;' + //@ !has - '//*[@id="reexport.Foo2"]/code' 'pub use crate::private_module::Bar as Foo2;' pub use crate::private_module::Bar as Foo2; //@ !has - '//*[@href="type.Yo.html"]' 'Yo' - //@ has - '//*[@id="reexport.Yo"]/code' 'pub use crate::Bar3 as Yo;' + //@ !has - '//*[@id="reexport.Yo"]/code' 'pub use crate::Bar3 as Yo;' pub use crate::Bar3 as Yo; //@ !has - '//*[@href="struct.Yo2.html"]' 'Yo2' - //@ has - '//*[@id="reexport.Yo2"]/code' 'pub use crate::FooFoo as Yo2;' + //@ !has - '//*[@id="reexport.Yo2"]/code' 'pub use crate::FooFoo as Yo2;' pub use crate::FooFoo as Yo2; // Checking that each file is also created as expected. @@ -70,19 +70,19 @@ pub mod single_reexport_no_inline { //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Re-exports' // Now we check that we don't have links to the items, just `pub use`. - //@ has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Public as XFoo;' + //@ !has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Public as XFoo;' //@ !has - '//*[@id="main-content"]//a' 'XFoo' #[doc(no_inline)] pub use crate::private_module::Public as XFoo; - //@ has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Bar as Foo2;' + //@ !has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Bar as Foo2;' //@ !has - '//*[@id="main-content"]//a' 'Foo2' #[doc(no_inline)] pub use crate::private_module::Bar as Foo2; - //@ has - '//*[@id="main-content"]//*' 'pub use crate::Bar3 as Yo;' + //@ !has - '//*[@id="main-content"]//*' 'pub use crate::Bar3 as Yo;' //@ !has - '//*[@id="main-content"]//a' 'Yo' #[doc(no_inline)] pub use crate::Bar3 as Yo; - //@ has - '//*[@id="main-content"]//*' 'pub use crate::FooFoo as Yo2;' + //@ !has - '//*[@id="main-content"]//*' 'pub use crate::FooFoo as Yo2;' //@ !has - '//*[@id="main-content"]//a' 'Yo2' #[doc(no_inline)] pub use crate::FooFoo as Yo2; diff --git a/tests/rustdoc/doc-hidden-source.rs b/tests/rustdoc/doc-hidden-source.rs new file mode 100644 index 0000000000000..b6bc622dd584f --- /dev/null +++ b/tests/rustdoc/doc-hidden-source.rs @@ -0,0 +1,16 @@ +// Test for . + +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ !has - '//*[@id="main-content"]//*[@class="struct"]' 'Bar' +#[doc(hidden)] +pub struct Bar; + +//@ !has - '//*' 'pub use crate::Bar as A;' +pub use crate::Bar as A; +//@ !has - '//*' 'pub use crate::A as B;' +pub use crate::A as B; +//@ has - '//dt/a[@class="struct"]' 'C' +#[doc(inline)] +pub use crate::Bar as C; diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs index 49ca2db6a2245..f6727de2cc67f 100644 --- a/tests/rustdoc/inline_cross/inline_hidden.rs +++ b/tests/rustdoc/inline_cross/inline_hidden.rs @@ -6,7 +6,7 @@ extern crate rustdoc_hidden; //@ has inline_hidden/index.html // Ensures this item is not inlined. -//@ has - '//*[@id="reexport.Foo"]/code' 'pub use rustdoc_hidden::Foo;' +//@ !has - '//*[@id="reexport.Foo"]/code' 'pub use rustdoc_hidden::Foo;' #[doc(no_inline)] pub use rustdoc_hidden::Foo; @@ -16,7 +16,7 @@ pub use rustdoc_hidden::Foo; pub use rustdoc_hidden::Foo as Inlined; // Even with this import, we should not see `Foo`. -//@ count - '//dt' 4 +//@ count - '//dt' 3 //@ has - '//dt/a[@class="struct"]' 'Bar' //@ has - '//dt/a[@class="fn"]' 'foo' pub use rustdoc_hidden::*; diff --git a/tests/rustdoc/reexport-attr-merge.rs b/tests/rustdoc/reexport-attr-merge.rs index e4a406c3845ad..aef302eb0b29a 100644 --- a/tests/rustdoc/reexport-attr-merge.rs +++ b/tests/rustdoc/reexport-attr-merge.rs @@ -18,7 +18,7 @@ pub use Foo1 as Foo2; // First we ensure that only the reexport `Bar2` and the inlined struct `Bar` // are inlined. -//@ count - '//a[@class="struct"]' 2 +//@ count - '//a[@class="struct"]' 1 // Then we check that `cfg` is displayed for base item, but not for intermediate re-exports. //@ has - '//*[@class="stab portability"]' 'foo' //@ !has - '//*[@class="stab portability"]' 'bar' @@ -29,5 +29,5 @@ pub use Foo2 as Bar; // This one should appear but `Bar2` won't be linked because there is no // `#[doc(inline)]`. -//@ has - '//*[@id="reexport.Bar2"]' 'pub use Foo2 as Bar2;' +//@ !has - '//*[@id="reexport.Bar2"]' 'pub use Foo2 as Bar2;' pub use Foo2 as Bar2; diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs index 8e194ef74fb82..bae2aa78ec7a3 100644 --- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -9,8 +9,8 @@ mod private_module { } //@ has 'foo/index.html' -//@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' +//@ !has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' pub use crate::private_module::Public as Foo; // Glob re-exports with no visible items should not be displayed. -//@ count - '//*[@class="item-table reexports"]/dt' 1 +//@ count - '//*[@class="item-table reexports"]/dt' 0 pub use crate::private_module::*; diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs index b912362f2987a..1468e9ad957f7 100644 --- a/tests/rustdoc/reexport-doc-hidden.rs +++ b/tests/rustdoc/reexport-doc-hidden.rs @@ -8,7 +8,7 @@ pub type Type = u32; //@ has 'foo/index.html' -//@ has - '//*[@id="reexport.Type2"]/code' 'pub use crate::Type as Type2;' +//@ !has - '//*[@id="reexport.Type2"]/code' 'pub use crate::Type as Type2;' pub use crate::Type as Type2; //@ count - '//*[@id="reexport.Type3"]' 0 @@ -21,5 +21,5 @@ macro_rules! foo { () => {}; } -//@ has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +//@ !has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport-hidden-macro.rs index 9b83bca3906d2..7345149c64522 100644 --- a/tests/rustdoc/reexport-hidden-macro.rs +++ b/tests/rustdoc/reexport-hidden-macro.rs @@ -5,7 +5,7 @@ //@ has 'foo/index.html' //@ has - '//*[@id="main-content"]//a[@href="macro.Macro2.html"]' 'Macro2' -//@ has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +//@ !has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' //@ has 'foo/macro.Macro2.html' //@ has - '//*[@class="docblock"]' 'Displayed' diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport-of-doc-hidden.rs index 21511bc2aea99..e901d0ff8a2bc 100644 --- a/tests/rustdoc/reexport-of-doc-hidden.rs +++ b/tests/rustdoc/reexport-of-doc-hidden.rs @@ -12,13 +12,13 @@ macro_rules! foo { } //@ has 'foo/index.html' -//@ has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +//@ !has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; -//@ has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' +//@ !has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' pub use crate::foo as Macro2; -//@ has - '//*[@id="reexport.Boo"]/code' 'pub use crate::Bar as Boo;' +//@ !has - '//*[@id="reexport.Boo"]/code' 'pub use crate::Bar as Boo;' pub use crate::Bar as Boo; -//@ has - '//*[@id="reexport.Boo2"]/code' 'pub use crate::Bar as Boo2;' +//@ !has - '//*[@id="reexport.Boo2"]/code' 'pub use crate::Bar as Boo2;' pub use crate::Bar as Boo2; pub fn fofo() {} @@ -30,9 +30,9 @@ pub use crate::fofo as f2; pub mod sub { //@ has 'foo/sub/index.html' - //@ has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' + //@ !has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; - //@ has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' + //@ !has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' pub use crate::foo as Macro2; //@ has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;' From a23566a57e4d53a35827becc2f65ce27951276c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 28 Feb 2025 21:39:25 +0000 Subject: [PATCH 21/40] Provide more context on resolve error caused from incorrect RTN When encountering a resolve E0575 error for an associated method (when a type was expected), see if it could have been an intended return type notation bound. ``` error[E0575]: expected associated type, found associated function `Trait::method` --> $DIR/bad-inputs-and-output.rs:31:36 | LL | fn foo_qualified() where ::method(i32): Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type | help: you might have meant to use the return type notation syntax | LL - fn foo_qualified() where ::method(i32): Send {} LL + fn foo_qualified() where T::method(..): Send {} | ``` --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_ast_lowering/src/path.rs | 1 - compiler/rustc_resolve/src/late.rs | 18 +++++++-- .../rustc_resolve/src/late/diagnostics.rs | 39 +++++++++++++++++- .../bad-inputs-and-output.fixed | 40 +++++++++++++++++++ .../bad-inputs-and-output.rs | 3 +- .../bad-inputs-and-output.stderr | 38 +++++++++++++----- 7 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.fixed diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 13edcc10c9e2a..2e175405da219 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -926,7 +926,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { - tracing::info!(?data, ?data.inputs); let err = match (&data.inputs[..], &data.output) { ([_, ..], FnRetTy::Default(_)) => { errors::BadReturnTypeNotation::Inputs { span: data.inputs_span } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6b6244b05aa9b..d00c797755f3f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -268,7 +268,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(data) => match generic_args_mode { GenericArgsMode::ReturnTypeNotation => { - tracing::info!(?data, ?data.inputs); let err = match (&data.inputs[..], &data.output) { ([_, ..], FnRetTy::Default(_)) => { BadReturnTypeNotation::Inputs { span: data.inputs_span } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f119ed55e7d1b..50bc2feb477dc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -623,7 +623,7 @@ pub(crate) struct UnnecessaryQualification<'ra> { pub removal_span: Span, } -#[derive(Default)] +#[derive(Default, Debug)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. current_trait_assoc_items: Option<&'ast [P]>, @@ -3146,6 +3146,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(AliasPossibility::No), Finalize::new(trait_ref.ref_id, trait_ref.path.span), RecordPartialRes::Yes, + None, ); self.diag_metadata.currently_processing_impl_trait = None; if let Some(def_id) = res.expect_full_res().opt_def_id() { @@ -4072,6 +4073,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { source, Finalize::new(id, path.span), RecordPartialRes::Yes, + None, ); } @@ -4083,14 +4085,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { source: PathSource<'ast>, finalize: Finalize, record_partial_res: RecordPartialRes, + parent_qself: Option<&QSelf>, ) -> PartialRes { let ns = source.namespace(); let Finalize { node_id, path_span, .. } = finalize; let report_errors = |this: &mut Self, res: Option| { if this.should_report_errs() { - let (err, candidates) = - this.smart_resolve_report_errors(path, None, path_span, source, res); + let (err, candidates) = this.smart_resolve_report_errors( + path, + None, + path_span, + source, + res, + parent_qself, + ); let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); @@ -4159,6 +4168,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path_span, PathSource::Type, None, + parent_qself, ); // There are two different error messages user might receive at @@ -4436,6 +4446,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(AliasPossibility::No), Finalize::new(finalize.node_id, qself.path_span), RecordPartialRes::No, + Some(&qself), ); if trait_res.expect_full_res() == Res::Err { @@ -4460,6 +4471,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::TraitItem(ns), Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span), RecordPartialRes::No, + Some(&qself), ); // The remaining segments (the `C` in our example) will diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0e14e7671b176..035f9abda86e6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -35,7 +35,7 @@ use super::NoConstantGenericsReason; use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::{ AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind, - LifetimeUseSet, RibKind, + LifetimeUseSet, QSelf, RibKind, }; use crate::ty::fast_reject::SimplifiedType; use crate::{ @@ -421,6 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { span: Span, source: PathSource<'_>, res: Option, + qself: Option<&QSelf>, ) -> (Diag<'tcx>, Vec) { debug!(?res, ?source); let base_error = self.make_base_error(path, span, source, res); @@ -453,6 +454,15 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.suggest_self_or_self_ref(&mut err, path, span); self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error); + self.detect_rtn_with_fully_qualified_path( + &mut err, + path, + following_seg, + span, + source, + res, + qself, + ); if self.suggest_self_ty(&mut err, source, path, span) || self.suggest_self_value(&mut err, source, path, span) { @@ -501,6 +511,33 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (err, candidates) } + fn detect_rtn_with_fully_qualified_path( + &self, + err: &mut Diag<'_>, + path: &[Segment], + following_seg: Option<&Segment>, + span: Span, + source: PathSource<'_>, + res: Option, + qself: Option<&QSelf>, + ) { + if let Some(Res::Def(DefKind::AssocFn, _)) = res + && let PathSource::TraitItem(TypeNS) = source + && let None = following_seg + && let Some(qself) = qself + && let TyKind::Path(None, ty_path) = &qself.ty.kind + && ty_path.segments.len() == 1 + && self.diag_metadata.current_where_predicate.is_some() + { + err.span_suggestion_verbose( + span, + "you might have meant to use the return type notation syntax", + format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident), + Applicability::MaybeIncorrect, + ); + } + } + fn detect_assoc_type_constraint_meant_as_path( &self, err: &mut Diag<'_>, diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.fixed b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.fixed new file mode 100644 index 0000000000000..7af986267aa67 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.fixed @@ -0,0 +1,40 @@ +//@ edition: 2021 +//@ run-rustfix +#![feature(return_type_notation)] +#![allow(dead_code)] + +trait Trait { + async fn method() {} +} + +fn foo>() {} +//~^ ERROR argument types not allowed with return type notation + +fn bar>() {} +//~^ ERROR return type not allowed with return type notation + +fn baz>() {} +//~^ ERROR return type notation arguments must be elided with `..` + +fn foo_path() where T::method(..): Send {} +//~^ ERROR argument types not allowed with return type notation + +fn bar_path() where T::method(..): Send {} +//~^ ERROR return type not allowed with return type notation + +fn bay_path() where T::method(..): Send {} +//~^ ERROR return type not allowed with return type notation + +fn baz_path() where T::method(..): Send {} +//~^ ERROR return type notation arguments must be elided with `..` + +fn foo_qualified() where T::method(..): Send {} +//~^ ERROR expected associated type + +fn bar_qualified() where T::method(..): Send {} +//~^ ERROR expected associated type + +fn baz_qualified() where T::method(..): Send {} +//~^ ERROR expected associated type + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 90fd2c2b4f326..983836e6433f0 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -1,6 +1,7 @@ //@ edition: 2021 - +//@ run-rustfix #![feature(return_type_notation)] +#![allow(dead_code)] trait Trait { async fn method() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index bd02b7d6534a9..e1245a04c7f7d 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,5 +1,5 @@ error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:24:45 + --> $DIR/bad-inputs-and-output.rs:25:45 | LL | fn bay_path() where T::method(..) -> (): Send {} | ^^^^^ @@ -11,25 +11,43 @@ LL + fn bay_path() where T::method(..): Send {} | error[E0575]: expected associated type, found associated function `Trait::method` - --> $DIR/bad-inputs-and-output.rs:30:36 + --> $DIR/bad-inputs-and-output.rs:31:36 | LL | fn foo_qualified() where ::method(i32): Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + | +help: you might have meant to use the return type notation syntax + | +LL - fn foo_qualified() where ::method(i32): Send {} +LL + fn foo_qualified() where T::method(..): Send {} + | error[E0575]: expected associated type, found associated function `Trait::method` - --> $DIR/bad-inputs-and-output.rs:33:36 + --> $DIR/bad-inputs-and-output.rs:34:36 | LL | fn bar_qualified() where ::method() -> (): Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + | +help: you might have meant to use the return type notation syntax + | +LL - fn bar_qualified() where ::method() -> (): Send {} +LL + fn bar_qualified() where T::method(..): Send {} + | error[E0575]: expected associated type, found associated function `Trait::method` - --> $DIR/bad-inputs-and-output.rs:36:36 + --> $DIR/bad-inputs-and-output.rs:37:36 | LL | fn baz_qualified() where ::method(): Send {} | ^^^^^^^^^^^^^^^^^^^^^^ not a associated type + | +help: you might have meant to use the return type notation syntax + | +LL - fn baz_qualified() where ::method(): Send {} +LL + fn baz_qualified() where T::method(..): Send {} + | error: argument types not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:9:23 + --> $DIR/bad-inputs-and-output.rs:10:23 | LL | fn foo>() {} | ^^^^^ @@ -41,7 +59,7 @@ LL + fn foo>() {} | error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:12:25 + --> $DIR/bad-inputs-and-output.rs:13:25 | LL | fn bar (): Send>>() {} | ^^^^^^ @@ -53,7 +71,7 @@ LL + fn bar>() {} | error: return type notation arguments must be elided with `..` - --> $DIR/bad-inputs-and-output.rs:15:23 + --> $DIR/bad-inputs-and-output.rs:16:23 | LL | fn baz>() {} | ^^ @@ -64,7 +82,7 @@ LL | fn baz>() {} | ++ error: argument types not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:18:40 + --> $DIR/bad-inputs-and-output.rs:19:40 | LL | fn foo_path() where T::method(i32): Send {} | ^^^^^ @@ -76,7 +94,7 @@ LL + fn foo_path() where T::method(..): Send {} | error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:21:42 + --> $DIR/bad-inputs-and-output.rs:22:42 | LL | fn bar_path() where T::method() -> (): Send {} | ^^^^^^ @@ -88,7 +106,7 @@ LL + fn bar_path() where T::method(..): Send {} | error: return type notation arguments must be elided with `..` - --> $DIR/bad-inputs-and-output.rs:27:40 + --> $DIR/bad-inputs-and-output.rs:28:40 | LL | fn baz_path() where T::method(): Send {} | ^^ From ddd04d03d1f271e31a54b777a54f8e2814ae365c Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Fri, 28 Feb 2025 13:04:23 -0800 Subject: [PATCH 22/40] Add timestamp to unstable feature usage metrics --- compiler/rustc_feature/src/unstable.rs | 16 +++++++++++++++- .../unstable-feature-usage-metrics/rmake.rs | 11 ++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 66c26a541f17f..09de30a89d00f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -1,6 +1,7 @@ //! List of the unstable feature gates. use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; use rustc_data_structures::fx::FxHashSet; use rustc_span::{Span, Symbol, sym}; @@ -681,11 +682,13 @@ impl Features { ) -> Result<(), Box> { #[derive(serde::Serialize)] struct LibFeature { + timestamp: u128, symbol: String, } #[derive(serde::Serialize)] struct LangFeature { + timestamp: u128, symbol: String, since: Option, } @@ -699,10 +702,20 @@ impl Features { let metrics_file = std::fs::File::create(metrics_path)?; let metrics_file = std::io::BufWriter::new(metrics_file); + let now = || { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should always be greater than the unix epoch") + .as_nanos() + }; + let lib_features = self .enabled_lib_features .iter() - .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() }) + .map(|EnabledLibFeature { gate_name, .. }| LibFeature { + symbol: gate_name.to_string(), + timestamp: now(), + }) .collect(); let lang_features = self @@ -711,6 +724,7 @@ impl Features { .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature { symbol: gate_name.to_string(), since: stable_since.map(|since| since.to_string()), + timestamp: now(), }) .collect(); diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs index 1397548a6fced..2183e28e89abe 100644 --- a/tests/run-make/unstable-feature-usage-metrics/rmake.rs +++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs @@ -58,12 +58,17 @@ fn test_metrics_dump() { ); let message = rfs::read_to_string(json_path); - let parsed: serde_json::Value = + let mut parsed: serde_json::Value = serde_json::from_str(&message).expect("metrics should be dumped as json"); + // remove timestamps + assert!(parsed["lib_features"][0]["timestamp"].is_number()); + assert!(parsed["lang_features"][0]["timestamp"].is_number()); + parsed["lib_features"][0]["timestamp"] = serde_json::json!(null); + parsed["lang_features"][0]["timestamp"] = serde_json::json!(null); let expected = serde_json::json!( { - "lib_features":[{"symbol":"ascii_char"}], - "lang_features":[{"symbol":"box_patterns","since":null}] + "lib_features":[{"symbol":"ascii_char", "timestamp":null}], + "lang_features":[{"symbol":"box_patterns","since":null, "timestamp":null}] } ); From ab31129956869f6dfc25417230061bad72de9081 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Feb 2025 20:10:37 +0000 Subject: [PATCH 23/40] Point of macro expansion from call expr if it involves macro var --- .../rustc_hir_typeck/src/method/suggest.rs | 23 ++++++++++++++++--- compiler/rustc_span/src/lib.rs | 23 +++++++++++++++++++ .../ui/methods/ident-from-macro-expansion.rs | 18 +++++++++++++++ .../methods/ident-from-macro-expansion.stderr | 21 +++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 tests/ui/methods/ident-from-macro-expansion.rs create mode 100644 tests/ui/methods/ident-from-macro-expansion.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 18218a7a0a641..41bd3933feec9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().used_trait_imports.insert(import_id); } - let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) { + let (span, expr_span, source, item_name, args) = match self.tcx.hir_node(call_id) { hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::MethodCall(segment, rcvr, args, _), span, @@ -194,6 +194,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node => unreachable!("{node:?}"), }; + // Try to get the span of the identifier within the expression's syntax context (if that's different). + let within_macro_span = span.within_macro(expr_span); + // Avoid suggestions when we don't know what's going on. if let Err(guar) = rcvr_ty.error_reported() { return guar; @@ -207,10 +210,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_id, source, args, - sugg_span, + expr_span, &mut no_match_data, expected, trait_missing_method, + within_macro_span, ), MethodError::Ambiguity(mut sources) => { @@ -221,6 +225,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "multiple applicable items in scope" ); err.span_label(item_name.span, format!("multiple `{item_name}` found")); + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } self.note_candidates_on_method_error( rcvr_ty, @@ -230,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, &mut err, &mut sources, - Some(sugg_span), + Some(expr_span), ); err.emit() } @@ -252,6 +259,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .span_if_local(def_id) .unwrap_or_else(|| self.tcx.def_span(def_id)); err.span_label(sp, format!("private {kind} defined here")); + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true); err.emit() } @@ -268,6 +278,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !needs_mut { err.span_label(bound_span, "this has a `Sized` requirement"); } + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } if !candidates.is_empty() { let help = format!( "{an}other candidate{s} {were} found in the following trait{s}", @@ -581,6 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, + within_macro_span: Option, ) -> ErrorGuaranteed { let mode = no_match_data.mode; let tcx = self.tcx; @@ -721,6 +735,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { ty_str = short_ty_str; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index bca9323a50d4c..d23e1825e6ea2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1057,6 +1057,29 @@ impl Span { } } + /// Returns the `Span` within the syntax context of "within". This is useful when + /// "self" is an expansion from a macro variable, since this can be used for + /// providing extra macro expansion context for certain errors. + /// + /// ```text + /// macro_rules! m { + /// ($ident:ident) => { ($ident,) } + /// } + /// + /// m!(outer_ident); + /// ``` + /// + /// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)` + /// expr, then this will return the span of the `$ident` macro variable. + pub fn within_macro(self, within: Span) -> Option { + match Span::prepare_to_combine(self, within) { + Ok((self_, _, parent)) if self_.lo != self.lo() && self.hi() != self_.hi => { + Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent)) + } + _ => None, + } + } + pub fn from_inner(self, inner: InnerSpan) -> Span { let span = self.data(); Span::new( diff --git a/tests/ui/methods/ident-from-macro-expansion.rs b/tests/ui/methods/ident-from-macro-expansion.rs new file mode 100644 index 0000000000000..38d2fee0e53c0 --- /dev/null +++ b/tests/ui/methods/ident-from-macro-expansion.rs @@ -0,0 +1,18 @@ +macro_rules! dot { + ($id:ident) => { + ().$id(); + } +} + +macro_rules! dispatch { + ($id:ident) => { + <()>::$id(); + } +} + +fn main() { + dot!(hello); + //~^ ERROR no method named `hello` found for unit type `()` in the current scope + dispatch!(hello); + //~^ ERROR no function or associated item named `hello` found for unit type `()` in the current scope +} diff --git a/tests/ui/methods/ident-from-macro-expansion.stderr b/tests/ui/methods/ident-from-macro-expansion.stderr new file mode 100644 index 0000000000000..b596ce29f6fee --- /dev/null +++ b/tests/ui/methods/ident-from-macro-expansion.stderr @@ -0,0 +1,21 @@ +error[E0599]: no method named `hello` found for unit type `()` in the current scope + --> $DIR/ident-from-macro-expansion.rs:14:10 + | +LL | ().$id(); + | --- due to this macro variable +... +LL | dot!(hello); + | ^^^^^ method not found in `()` + +error[E0599]: no function or associated item named `hello` found for unit type `()` in the current scope + --> $DIR/ident-from-macro-expansion.rs:16:15 + | +LL | <()>::$id(); + | --- due to this macro variable +... +LL | dispatch!(hello); + | ^^^^^ function or associated item not found in `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. From e4dfca8ac240d517e5d7008333fd7d3367d0176f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Feb 2025 20:20:54 +0000 Subject: [PATCH 24/40] Point out macro expansion ident in resolver errors too --- compiler/rustc_hir_typeck/src/method/suggest.rs | 3 ++- compiler/rustc_resolve/src/late/diagnostics.rs | 6 ++++++ tests/ui/hygiene/generate-mod.stderr | 6 ++++++ tests/ui/hygiene/globs.stderr | 6 ++++++ tests/ui/macros/macro-parameter-span.stderr | 3 +++ tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr | 3 +++ 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 41bd3933feec9..09e1390cc3ecd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -194,7 +194,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node => unreachable!("{node:?}"), }; - // Try to get the span of the identifier within the expression's syntax context (if that's different). + // Try to get the span of the identifier within the expression's syntax context + // (if that's different). let within_macro_span = span.within_macro(expr_span); // Avoid suggestions when we don't know what's going on. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0e14e7671b176..c86305e23d1d7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -429,6 +429,12 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone()); err.code(code); + // Try to get the span of the identifier within the path's syntax context + // (if that's different). + if let Some(within_macro_span) = base_error.span.within_macro(span) { + err.span_label(within_macro_span, "within this macro"); + } + self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg); self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); diff --git a/tests/ui/hygiene/generate-mod.stderr b/tests/ui/hygiene/generate-mod.stderr index 32a2e145ca942..58b9c642dabe3 100644 --- a/tests/ui/hygiene/generate-mod.stderr +++ b/tests/ui/hygiene/generate-mod.stderr @@ -1,12 +1,18 @@ error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:35:13 | +LL | type A = $FromOutside; + | ------------ due to this macro variable +... LL | genmod!(FromOutside, Outer); | ^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:35:26 | +LL | struct $Outer; + | ------ due to this macro variable +... LL | genmod!(FromOutside, Outer); | ^^^^^ not found in this scope diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr index 3f7a0ae7efa1b..31f25b182f1f5 100644 --- a/tests/ui/hygiene/globs.stderr +++ b/tests/ui/hygiene/globs.stderr @@ -50,6 +50,9 @@ error[E0425]: cannot find function `f` in this scope LL | n!(f); | ----- in this macro invocation ... +LL | $j(); + | -- due to this macro variable +... LL | n!(f); | ^ not found in this scope | @@ -63,6 +66,9 @@ error[E0425]: cannot find function `f` in this scope LL | n!(f); | ----- in this macro invocation ... +LL | $j(); + | -- due to this macro variable +... LL | f | ^ not found in this scope | diff --git a/tests/ui/macros/macro-parameter-span.stderr b/tests/ui/macros/macro-parameter-span.stderr index 247750a8ad705..44c8c56dff999 100644 --- a/tests/ui/macros/macro-parameter-span.stderr +++ b/tests/ui/macros/macro-parameter-span.stderr @@ -1,6 +1,9 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/macro-parameter-span.rs:11:9 | +LL | $id + | --- due to this macro variable +... LL | x | ^ not found in this scope diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index ce7694ecb1da3..d9646760cea92 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -338,6 +338,9 @@ LL | no_curly__no_rhs_dollar__no_round!(a); error[E0425]: cannot find value `a` in this scope --> $DIR/syntax-errors.rs:152:37 | +LL | ( $i:ident ) => { count($i) }; + | -- due to this macro variable +... LL | no_curly__rhs_dollar__no_round!(a); | ^ not found in this scope From 06072468fe8de249a39d2fcc42cea51db2649a80 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Feb 2025 20:36:15 +0000 Subject: [PATCH 25/40] Fix associated type errors too --- compiler/rustc_hir_analysis/messages.ftl | 2 ++ compiler/rustc_hir_analysis/src/errors.rs | 2 ++ .../src/hir_ty_lowering/errors.rs | 3 +++ .../ident-from-macro-expansion.rs | 23 +++++++++++++++++++ .../ident-from-macro-expansion.stderr | 22 ++++++++++++++++++ 5 files changed, 52 insertions(+) create mode 100644 tests/ui/associated-types/ident-from-macro-expansion.rs create mode 100644 tests/ui/associated-types/ident-from-macro-expansion.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 3f75cce009225..c2a6b5a890ec1 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -620,6 +620,8 @@ hir_analysis_variances_of = {$variances} hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause .label = `main` cannot have a `where` clause +hir_analysis_within_macro = due to this macro variable + hir_analysis_wrong_number_of_generic_arguments_to_intrinsic = intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} .label = expected {$expected} {$descr} {$expected -> diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 852533ff5c954..78b28048c8b07 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -84,6 +84,8 @@ pub(crate) struct AssocItemNotFound<'a> { pub label: Option>, #[subdiagnostic] pub sugg: Option>, + #[label(hir_analysis_within_macro)] + pub within_macro_span: Option, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 922578792ba8b..156ddb8f2aaba 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -151,6 +151,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qself: &qself_str, label: None, sugg: None, + // Try to get the span of the identifier within the path's syntax context + // (if that's different). + within_macro_span: assoc_name.span.within_macro(span), }; if is_dummy { diff --git a/tests/ui/associated-types/ident-from-macro-expansion.rs b/tests/ui/associated-types/ident-from-macro-expansion.rs new file mode 100644 index 0000000000000..6aabe4571406c --- /dev/null +++ b/tests/ui/associated-types/ident-from-macro-expansion.rs @@ -0,0 +1,23 @@ +trait Trait {} +impl Trait for () {} + +macro_rules! fully_qualified { + ($id:ident) => { + <() as Trait>::$id + } +} + +macro_rules! type_dependent { + ($t:ident, $id:ident) => { + T::$id + } +} + +fn t() { + let x: fully_qualified!(Assoc); + //~^ ERROR cannot find associated type `Assoc` in trait `Trait` + let x: type_dependent!(T, Assoc); + //~^ ERROR associated type `Assoc` not found for `T` +} + +fn main() {} diff --git a/tests/ui/associated-types/ident-from-macro-expansion.stderr b/tests/ui/associated-types/ident-from-macro-expansion.stderr new file mode 100644 index 0000000000000..dabf13c2c1726 --- /dev/null +++ b/tests/ui/associated-types/ident-from-macro-expansion.stderr @@ -0,0 +1,22 @@ +error[E0576]: cannot find associated type `Assoc` in trait `Trait` + --> $DIR/ident-from-macro-expansion.rs:17:29 + | +LL | <() as Trait>::$id + | --- due to this macro variable +... +LL | let x: fully_qualified!(Assoc); + | ^^^^^ not found in `Trait` + +error[E0220]: associated type `Assoc` not found for `T` + --> $DIR/ident-from-macro-expansion.rs:19:31 + | +LL | T::$id + | --- due to this macro variable +... +LL | let x: type_dependent!(T, Assoc); + | ^^^^^ associated type `Assoc` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0220, E0576. +For more information about an error, try `rustc --explain E0220`. From 09e584671b439dc8a9d57cc900cc26668a69ddea Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Feb 2025 21:37:01 +0000 Subject: [PATCH 26/40] Also note struct access, and fix macro expansion from foreign crates --- .../src/hir_ty_lowering/errors.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 35 ++++++++++++------- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 6 ++-- compiler/rustc_span/src/lib.rs | 12 +++++-- .../ui/structs/ident-from-macro-expansion.rs | 19 ++++++++++ .../structs/ident-from-macro-expansion.stderr | 14 ++++++++ 7 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 tests/ui/structs/ident-from-macro-expansion.rs create mode 100644 tests/ui/structs/ident-from-macro-expansion.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 156ddb8f2aaba..6b9c1c0b309af 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -153,7 +153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { sugg: None, // Try to get the span of the identifier within the path's syntax context // (if that's different). - within_macro_span: assoc_name.span.within_macro(span), + within_macro_span: assoc_name.span.within_macro(span, tcx.sess.source_map()), }; if is_dummy { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dec1779d92ca4..7f67e524fc4a8 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3069,7 +3069,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}", ident, base, expr, base_ty ); - let mut err = self.no_such_field_err(ident, base_ty, base.hir_id); + let mut err = self.no_such_field_err(ident, base_ty, expr); match *base_ty.peel_refs().kind() { ty::Array(_, len) => { @@ -3282,18 +3282,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> { + fn no_such_field_err( + &self, + field: Ident, + base_ty: Ty<'tcx>, + expr: &hir::Expr<'tcx>, + ) -> Diag<'_> { let span = field.span; - debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); + debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, base_ty); - let mut err = self.dcx().create_err(NoFieldOnType { span, ty: expr_t, field }); - if expr_t.references_error() { + let mut err = self.dcx().create_err(NoFieldOnType { span, ty: base_ty, field }); + if base_ty.references_error() { err.downgrade_to_delayed_bug(); } + if let Some(within_macro_span) = span.within_macro(expr.span, self.tcx.sess.source_map()) { + err.span_label(within_macro_span, "due to this macro variable"); + } + // try to add a suggestion in case the field is a nested field of a field of the Adt - let mod_id = self.tcx.parent_module(id).to_def_id(); - let (ty, unwrap) = if let ty::Adt(def, args) = expr_t.kind() + let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); + let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() && (self.tcx.is_diagnostic_item(sym::Result, def.did()) || self.tcx.is_diagnostic_item(sym::Option, def.did())) && let Some(arg) = args.get(0) @@ -3301,10 +3310,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { (ty, "unwrap().") } else { - (expr_t, "") + (base_ty, "") }; for (found_fields, args) in - self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id) + self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) { let field_names = found_fields.iter().map(|field| field.name).collect::>(); let mut candidate_fields: Vec<_> = found_fields @@ -3317,7 +3326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, vec![], mod_id, - id, + expr.hir_id, ) }) .map(|mut field_path| { @@ -3328,7 +3337,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_fields.sort(); let len = candidate_fields.len(); - if len > 0 { + // Don't suggest `.field` if the base expr is from a different + // syntax context than the field. + if len > 0 && expr.span.eq_ctxt(field.span) { err.span_suggestions( field.span.shrink_to_lo(), format!( @@ -3963,7 +3974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (), }; - self.no_such_field_err(field, container, expr.hir_id).emit(); + self.no_such_field_err(field, container, expr).emit(); break; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 09e1390cc3ecd..cb1e89fb9e593 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Try to get the span of the identifier within the expression's syntax context // (if that's different). - let within_macro_span = span.within_macro(expr_span); + let within_macro_span = span.within_macro(expr_span, self.tcx.sess.source_map()); // Avoid suggestions when we don't know what's going on. if let Err(guar) = rcvr_ty.error_reported() { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c86305e23d1d7..47b21f86641ba 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -431,8 +431,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Try to get the span of the identifier within the path's syntax context // (if that's different). - if let Some(within_macro_span) = base_error.span.within_macro(span) { - err.span_label(within_macro_span, "within this macro"); + if let Some(within_macro_span) = + base_error.span.within_macro(span, self.r.tcx.sess.source_map()) + { + err.span_label(within_macro_span, "due to this macro variable"); } self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d23e1825e6ea2..798e186a94b1a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1071,9 +1071,17 @@ impl Span { /// /// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)` /// expr, then this will return the span of the `$ident` macro variable. - pub fn within_macro(self, within: Span) -> Option { + pub fn within_macro(self, within: Span, sm: &SourceMap) -> Option { match Span::prepare_to_combine(self, within) { - Ok((self_, _, parent)) if self_.lo != self.lo() && self.hi() != self_.hi => { + // Only return something if it doesn't overlap with the original span, + // and the span isn't "imported" (i.e. from unavailable sources). + // FIXME: This does limit the usefulness of the error when the macro is + // from a foreign crate; we could also take into account `-Zmacro-backtrace`, + // which doesn't redact this span (but that would mean passing in even more + // args to this function, lol). + Ok((self_, _, parent)) + if self_.hi < self.lo() || self.hi() < self_.lo && !sm.is_imported(within) => + { Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent)) } _ => None, diff --git a/tests/ui/structs/ident-from-macro-expansion.rs b/tests/ui/structs/ident-from-macro-expansion.rs new file mode 100644 index 0000000000000..56d31a4256168 --- /dev/null +++ b/tests/ui/structs/ident-from-macro-expansion.rs @@ -0,0 +1,19 @@ +struct Foo { + inner: Inner, +} + +struct Inner { + y: i32, +} + +macro_rules! access { + ($expr:expr, $ident:ident) => { + $expr.$ident + } +} + +fn main() { + let k = Foo { inner: Inner { y: 0 } }; + access!(k, y); + //~^ ERROR no field `y` on type `Foo` +} diff --git a/tests/ui/structs/ident-from-macro-expansion.stderr b/tests/ui/structs/ident-from-macro-expansion.stderr new file mode 100644 index 0000000000000..be2ab7c2e9966 --- /dev/null +++ b/tests/ui/structs/ident-from-macro-expansion.stderr @@ -0,0 +1,14 @@ +error[E0609]: no field `y` on type `Foo` + --> $DIR/ident-from-macro-expansion.rs:17:16 + | +LL | $expr.$ident + | ------ due to this macro variable +... +LL | access!(k, y); + | ^ unknown field + | + = note: available field is: `inner` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0609`. From 69c46515edc86dea961e1565ee2b34311ddaeb35 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:01:00 +0100 Subject: [PATCH 27/40] ci: use ubuntu 24 on arm large runner --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1504e5c60ce7e..69a39b6eec2f7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -54,7 +54,7 @@ runners: <<: *base-job - &job-aarch64-linux-8c - os: ubuntu-22.04-arm64-8core-32gb + os: ubuntu-24.04-arm64-8core-32gb <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests From da3e73654f311869c052f218e37871a2f4381c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Fri, 28 Feb 2025 20:54:10 +0100 Subject: [PATCH 28/40] Clarify why InhabitedPredicate::instantiate_opt exists At first glance, the extra casework seems pointless and needlessly error-prone. Clarify that there is a reason for it being there. --- .../rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index 505c7278176f3..86ef07dff5f29 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -236,6 +236,11 @@ impl<'tcx> InhabitedPredicate<'tcx> { self.instantiate_opt(tcx, args).unwrap_or(self) } + /// Same as [`Self::instantiate`], but if there is no generics to + /// instantiate, returns `None`. This is useful because it lets us avoid + /// allocating a recursive copy of everything when the result is unchanged. + /// + /// Only used to implement `instantiate` itself. fn instantiate_opt(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Option { match self { Self::ConstIsZero(c) => { From a3d63fb0d488e4db52e0fe672f0cf2040840f2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Mon, 3 Mar 2025 23:52:22 +0100 Subject: [PATCH 29/40] InhabitedPredicate: avoid using a wildcard branch This is error-prone. Explicitly write down which cases don't need anything substituted. Turn the `OpaqueType` case, which currently seems to be unreachable, into a `bug!`. --- .../rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index 86ef07dff5f29..953ad62be0a86 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -265,7 +265,10 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True), Some(a) => Some(a.or(tcx, b.instantiate_opt(tcx, args).unwrap_or(b))), }, - _ => None, + Self::True | Self::False | Self::NotInModule(_) => None, + Self::OpaqueType(_) => { + bug!("unexpected OpaqueType in InhabitedPredicate"); + } } } } From 3d62b279ddc2095b94aa5921540b27f3003365ff Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Feb 2025 01:28:32 +0000 Subject: [PATCH 30/40] Ensure that negative auto impls are always applicable --- compiler/rustc_data_structures/src/marker.rs | 10 +- .../check/{dropck.rs => always_applicable.rs} | 149 +++++++++++++----- compiler/rustc_hir_analysis/src/check/mod.rs | 6 +- .../rustc_hir_analysis/src/coherence/mod.rs | 26 +-- compiler/rustc_middle/src/traits/mod.rs | 4 +- .../src/error_reporting/traits/suggestions.rs | 2 +- library/core/src/convert/mod.rs | 1 - ...herence-conflicting-negative-trait-impl.rs | 8 +- ...nce-conflicting-negative-trait-impl.stderr | 31 +++- ...mpl-trait-for-marker-trait-negative.stderr | 20 +-- tests/ui/coherence/coherence-orphan.rs | 5 +- .../coherence-overlap-negative-impls.rs | 4 +- .../coherence-overlap-negative-impls.stderr | 16 ++ tests/ui/issues/issue-106755.rs | 5 +- tests/ui/issues/issue-106755.stderr | 31 +++- .../specialization/defaultimpl/validation.rs | 15 +- .../defaultimpl/validation.stderr | 28 ++-- .../specialization-overlap-negative.rs | 4 +- .../specialization-overlap-negative.stderr | 17 +- 19 files changed, 275 insertions(+), 107 deletions(-) rename compiler/rustc_hir_analysis/src/check/{dropck.rs => always_applicable.rs} (62%) create mode 100644 tests/ui/coherence/coherence-overlap-negative-impls.stderr diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 6ae97222f77fd..4cacc269709a9 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,3 +1,5 @@ +use std::alloc::Allocator; + #[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` @@ -28,8 +30,8 @@ impls_dyn_send_neg!( [*const T where T: ?Sized] [*mut T where T: ?Sized] [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] + [std::rc::Rc where T: ?Sized, A: Allocator] + [std::rc::Weak where T: ?Sized, A: Allocator] [std::sync::MutexGuard<'_, T> where T: ?Sized] [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] @@ -96,8 +98,8 @@ impls_dyn_sync_neg!( [std::cell::RefCell where T: ?Sized] [std::cell::UnsafeCell where T: ?Sized] [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] + [std::rc::Rc where T: ?Sized, A: Allocator] + [std::rc::Weak where T: ?Sized, A: Allocator] [std::cell::OnceCell where T] [std::sync::mpsc::Receiver where T] [std::sync::mpsc::Sender where T] diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs similarity index 62% rename from compiler/rustc_hir_analysis/src/check/dropck.rs rename to compiler/rustc_hir_analysis/src/check/always_applicable.rs index d7dfe482da449..64377ffa34761 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -1,8 +1,15 @@ +//! This module contains methods that assist in checking that impls are general +//! enough, i.e. that they always apply to every valid instantaiton of the ADT +//! they're implemented for. +//! +//! This is necessary for `Drop` and negative impls to be well-formed. + use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::span_bug; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -27,11 +34,12 @@ use crate::hir::def_id::{DefId, LocalDefId}; /// 3. Any bounds on the generic parameters must be reflected in the /// struct/enum definition for the nominal type itself (i.e. /// cannot do `struct S; impl Drop for S { ... }`). -/// pub(crate) fn check_drop_impl( tcx: TyCtxt<'_>, drop_impl_did: DefId, ) -> Result<(), ErrorGuaranteed> { + let drop_impl_did = drop_impl_did.expect_local(); + match tcx.impl_polarity(drop_impl_did) { ty::ImplPolarity::Positive => {} ty::ImplPolarity::Negative => { @@ -45,55 +53,107 @@ pub(crate) fn check_drop_impl( })); } } - let dtor_self_type = tcx.type_of(drop_impl_did).instantiate_identity(); - match dtor_self_type.kind() { + + tcx.ensure_ok().orphan_check_impl(drop_impl_did)?; + + let dtor_impl_trait_ref = tcx.impl_trait_ref(drop_impl_did).unwrap().instantiate_identity(); + + match dtor_impl_trait_ref.self_ty().kind() { ty::Adt(adt_def, adt_to_impl_args) => { - ensure_drop_params_and_item_params_correspond( + ensure_impl_params_and_item_params_correspond( tcx, - drop_impl_did.expect_local(), + drop_impl_did, adt_def.did(), adt_to_impl_args, )?; - ensure_drop_predicates_are_implied_by_item_defn( + ensure_impl_predicates_are_implied_by_item_defn( tcx, - drop_impl_did.expect_local(), - adt_def.did().expect_local(), + drop_impl_did, + adt_def.did(), adt_to_impl_args, ) } _ => { - // Destructors only work on nominal types. This was - // already checked by coherence, but compilation may - // not have been terminated. - let span = tcx.def_span(drop_impl_did); - let reported = tcx.dcx().span_delayed_bug( - span, - format!("should have been rejected by coherence check: {dtor_self_type}"), - ); - Err(reported) + span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop"); } } } -fn ensure_drop_params_and_item_params_correspond<'tcx>( +pub(crate) fn check_negative_auto_trait_impl<'tcx>( tcx: TyCtxt<'tcx>, - drop_impl_did: LocalDefId, - self_type_did: DefId, + impl_def_id: LocalDefId, + impl_trait_ref: ty::TraitRef<'tcx>, + polarity: ty::ImplPolarity, +) -> Result<(), ErrorGuaranteed> { + let ty::ImplPolarity::Negative = polarity else { + return Ok(()); + }; + + if !tcx.trait_is_auto(impl_trait_ref.def_id) { + return Ok(()); + } + + if tcx.defaultness(impl_def_id).is_default() { + tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative"); + } + + tcx.ensure_ok().orphan_check_impl(impl_def_id)?; + + match impl_trait_ref.self_ty().kind() { + ty::Adt(adt_def, adt_to_impl_args) => { + ensure_impl_params_and_item_params_correspond( + tcx, + impl_def_id, + adt_def.did(), + adt_to_impl_args, + )?; + + ensure_impl_predicates_are_implied_by_item_defn( + tcx, + impl_def_id, + adt_def.did(), + adt_to_impl_args, + ) + } + _ => { + if tcx.features().auto_traits() { + // NOTE: We ignore the applicability check for negative auto impls + // defined in libcore. In the (almost impossible) future where we + // stabilize auto impls, then the proper applicability check MUST + // be implemented here to handle non-ADT rigid types. + Ok(()) + } else { + span_bug!(tcx.def_span(impl_def_id), "incoherent impl of negative auto trait"); + } + } + } +} + +fn ensure_impl_params_and_item_params_correspond<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: LocalDefId, + adt_def_id: DefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else { return Ok(()); }; - let drop_impl_span = tcx.def_span(drop_impl_did); - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_descr(self_type_did); + let drop_impl_span = tcx.def_span(impl_def_id); + let item_span = tcx.def_span(adt_def_id); + let self_descr = tcx.def_descr(adt_def_id); + let polarity = match tcx.impl_polarity(impl_def_id) { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; + let trait_name = tcx + .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait")); let mut err = struct_span_code_err!( tcx.dcx(), drop_impl_span, E0366, - "`Drop` impls cannot be specialized" + "`{polarity}{trait_name}` impls cannot be specialized", ); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { @@ -116,17 +176,22 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( /// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be /// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are /// implied by the ADT being well formed. -fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( +fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( tcx: TyCtxt<'tcx>, - drop_impl_def_id: LocalDefId, - adt_def_id: LocalDefId, + impl_def_id: LocalDefId, + adt_def_id: DefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); - + let impl_span = tcx.def_span(impl_def_id.to_def_id()); + let trait_name = tcx + .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait")); + let polarity = match tcx.impl_polarity(impl_def_id) { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the // self ty of the implementation is allowed to know just from it being a @@ -145,17 +210,21 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let adt_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); - let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id()); + let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id()); let fresh_adt_ty = - tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty(); + tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty(); ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty) - .unwrap(); + .expect("equating fully generic trait ref should never fail"); - for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) { - let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); + for (clause, span) in tcx.predicates_of(impl_def_id).instantiate(tcx, fresh_impl_args) { + let normalize_cause = traits::ObligationCause::misc(span, impl_def_id); let pred = ocx.normalize(&normalize_cause, adt_env, clause); - let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl); + let cause = traits::ObligationCause::new( + span, + impl_def_id, + ObligationCauseCode::AlwaysApplicableImpl, + ); ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred)); } @@ -173,13 +242,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let root_predicate = error.root_obligation.predicate; if root_predicates.insert(root_predicate) { let item_span = tcx.def_span(adt_def_id); - let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + let self_descr = tcx.def_descr(adt_def_id); guar = Some( struct_span_code_err!( tcx.dcx(), error.root_obligation.cause.span, E0367, - "`Drop` impl requires `{root_predicate}` \ + "`{polarity}{trait_name}` impl requires `{root_predicate}` \ but the {self_descr} it is implemented for does not", ) .with_span_note(item_span, "the implementor must specify the same requirement") @@ -190,12 +259,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( return Err(guar.unwrap()); } - let errors = ocx.infcx.resolve_regions(adt_def_id, adt_env, []); + let errors = ocx.infcx.resolve_regions(impl_def_id, adt_env, []); if !errors.is_empty() { let mut guar = None; for error in errors { let item_span = tcx.def_span(adt_def_id); - let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + let self_descr = tcx.def_descr(adt_def_id); let outlives = match error { RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"), RegionResolutionError::GenericBoundFailure(_, generic, r) => { @@ -212,7 +281,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( tcx.dcx(), error.origin().span(), E0367, - "`Drop` impl requires `{outlives}` \ + "`{polarity}{trait_name}` impl requires `{outlives}` \ but the {self_descr} it is implemented for does not", ) .with_span_note(item_span, "the implementor must specify the same requirement") diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 1c5455710db8a..d72d5b4fa19d4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -62,9 +62,9 @@ a type parameter). */ +pub mod always_applicable; mod check; mod compare_impl_item; -pub mod dropck; mod entry; pub mod intrinsic; pub mod intrinsicck; @@ -113,11 +113,11 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) + tcx.calculate_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_async_dtor(def_id.to_def_id(), dropck::check_drop_impl) + tcx.calculate_async_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 0245d4c9fe4b6..b5c6c2f386192 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -16,6 +16,7 @@ use rustc_span::{ErrorGuaranteed, sym}; use rustc_type_ir::elaborate; use tracing::debug; +use crate::check::always_applicable; use crate::errors; mod builtin; @@ -24,11 +25,12 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; -fn check_impl( - tcx: TyCtxt<'_>, +fn check_impl<'tcx>( + tcx: TyCtxt<'tcx>, impl_def_id: LocalDefId, - trait_ref: ty::TraitRef<'_>, - trait_def: &ty::TraitDef, + trait_ref: ty::TraitRef<'tcx>, + trait_def: &'tcx ty::TraitDef, + polarity: ty::ImplPolarity, ) -> Result<(), ErrorGuaranteed> { debug!( "(checking implementation) adding impl for trait '{:?}', item '{}'", @@ -44,6 +46,12 @@ fn check_impl( enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id, trait_def) .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id, trait_def)) + .and(always_applicable::check_negative_auto_trait_impl( + tcx, + impl_def_id, + trait_ref, + polarity, + )) } fn enforce_trait_manually_implementable( @@ -154,16 +162,16 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> let mut res = tcx.ensure_ok().specialization_graph_of(def_id); for &impl_def_id in impls { - let trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let trait_ref = trait_header.trait_ref.instantiate_identity(); + let impl_header = tcx.impl_trait_header(impl_def_id).unwrap(); + let trait_ref = impl_header.trait_ref.instantiate_identity(); let trait_def = tcx.trait_def(trait_ref.def_id); res = res - .and(check_impl(tcx, impl_def_id, trait_ref, trait_def)) + .and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity)) .and(check_object_overlap(tcx, impl_def_id, trait_ref)) - .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def)) + .and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def)) .and(tcx.ensure_ok().orphan_check_impl(impl_def_id)) - .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header)); + .and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header)); } res diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d033ecc75dbe5..af38748d5b2a6 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -397,9 +397,9 @@ pub enum ObligationCauseCode<'tcx> { RustCall, - /// Obligations to prove that a `std::ops::Drop` impl is not stronger than + /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than /// the ADT it's being implemented for. - DropImpl, + AlwaysApplicableImpl, /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy` ConstParam(Ty<'tcx>), 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 b85c18c53121f..0178400414cb2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2695,7 +2695,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::LetElse | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) - | ObligationCauseCode::DropImpl + | ObligationCauseCode::AlwaysApplicableImpl | ObligationCauseCode::ConstParam(_) | ObligationCauseCode::ReferenceOutlivesReferent(..) | ObligationCauseCode::ObjectTypeBound(..) => {} diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index e468f4f0f7e66..43fd54f881dae 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -778,7 +778,6 @@ impl From for T { /// /// [#64715]: https://github.com/rust-lang/rust/issues/64715 #[stable(feature = "convert_infallible", since = "1.34.0")] -#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead. #[rustc_reservation_impl = "permitting this impl would forbid us from adding \ `impl From for T` later; see rust-lang/rust#64715 for details"] impl From for T { diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs index 24b878927530c..15ca0577e4acb 100644 --- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs +++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs @@ -8,10 +8,14 @@ struct TestType(::std::marker::PhantomData); unsafe impl Send for TestType {} -impl !Send for TestType {} //~ ERROR found both positive and negative implementation +impl !Send for TestType {} +//~^ ERROR found both positive and negative implementation +//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not -unsafe impl Send for TestType {} //~ ERROR conflicting implementations +unsafe impl Send for TestType {} +//~^ ERROR conflicting implementations impl !Send for TestType {} +//~^ ERROR `!Send` impls cannot be specialized fn main() {} diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr index 2463f38a92251..c6aed150201d8 100644 --- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr +++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr @@ -8,7 +8,7 @@ LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` - --> $DIR/coherence-conflicting-negative-trait-impl.rs:13:1 + --> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1 | LL | unsafe impl Send for TestType {} | ------------------------------------------------------ first implementation here @@ -16,7 +16,32 @@ LL | unsafe impl Send for TestType {} LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -error: aborting due to 2 previous errors +error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not + --> $DIR/coherence-conflicting-negative-trait-impl.rs:11:9 + | +LL | impl !Send for TestType {} + | ^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/coherence-conflicting-negative-trait-impl.rs:7:1 + | +LL | struct TestType(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^ + +error[E0366]: `!Send` impls cannot be specialized + --> $DIR/coherence-conflicting-negative-trait-impl.rs:18:1 + | +LL | impl !Send for TestType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `i32` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/coherence-conflicting-negative-trait-impl.rs:7:1 + | +LL | struct TestType(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0119, E0751. +Some errors have detailed explanations: E0119, E0366, E0367, E0751. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index 77d1bdee5acf1..bc81dd6f286dd 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -1,9 +1,3 @@ -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 - | -LL | impl !Marker1 for dyn Object + Marker2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` - error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 | @@ -12,11 +6,11 @@ LL | impl !Marker1 for dyn Object + Marker2 {} | = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 | -LL | impl !Marker2 for dyn Object + Marker2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` +LL | impl !Marker1 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 @@ -26,6 +20,12 @@ LL | impl !Marker2 for dyn Object + Marker2 {} | = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 + | +LL | impl !Marker2 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` + error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1 | diff --git a/tests/ui/coherence/coherence-orphan.rs b/tests/ui/coherence/coherence-orphan.rs index aee6647a78819..665fa15c56e53 100644 --- a/tests/ui/coherence/coherence-orphan.rs +++ b/tests/ui/coherence/coherence-orphan.rs @@ -8,12 +8,13 @@ use lib::TheTrait; struct TheType; impl TheTrait for isize {} -//~^ ERROR E0117 +//~^ ERROR only traits defined in the current crate can be implemented for primitive types impl TheTrait for isize {} impl TheTrait for TheType {} -impl !Send for Vec {} //~ ERROR E0117 +impl !Send for Vec {} +//~^ ERROR only traits defined in the current crate can be implemented for types defined outside of the crate fn main() {} diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.rs b/tests/ui/coherence/coherence-overlap-negative-impls.rs index ffcd56817e5c2..ba90a37cb2aab 100644 --- a/tests/ui/coherence/coherence-overlap-negative-impls.rs +++ b/tests/ui/coherence/coherence-overlap-negative-impls.rs @@ -1,6 +1,3 @@ -//@ check-pass -//@ known-bug: #74629 - // Should fail. The `0` and `1` impls overlap, violating coherence. Eg, with // `T = Test, F = ()`, all bounds are true, making both impls applicable. // `Test: Fold`, `Test: Fold<()>` are true because of `2`. @@ -39,6 +36,7 @@ mod private { pub auto trait NotNil {} impl !NotNil for Is {} + //~^ ERROR `!NotNil` impls cannot be specialized } fn main() {} diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.stderr b/tests/ui/coherence/coherence-overlap-negative-impls.stderr new file mode 100644 index 0000000000000..fe22cf61b753c --- /dev/null +++ b/tests/ui/coherence/coherence-overlap-negative-impls.stderr @@ -0,0 +1,16 @@ +error[E0366]: `!NotNil` impls cannot be specialized + --> $DIR/coherence-overlap-negative-impls.rs:38:5 + | +LL | impl !NotNil for Is {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Nil` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/coherence-overlap-negative-impls.rs:35:5 + | +LL | pub struct Is(T); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0366`. diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/issues/issue-106755.rs index 689b1d885ae60..d7e7122ebda16 100644 --- a/tests/ui/issues/issue-106755.rs +++ b/tests/ui/issues/issue-106755.rs @@ -10,10 +10,13 @@ struct TestType(::std::marker::PhantomData); unsafe impl Send for TestType {} -impl !Send for TestType {} //~ ERROR found both positive and negative implementation +impl !Send for TestType {} +//~^ ERROR found both positive and negative implementation +//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not unsafe impl Send for TestType {} //~ ERROR conflicting implementations impl !Send for TestType {} +//~^ ERROR `!Send` impls cannot be specialized fn main() {} diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/issues/issue-106755.stderr index 543970340620d..da6b8c5c56325 100644 --- a/tests/ui/issues/issue-106755.stderr +++ b/tests/ui/issues/issue-106755.stderr @@ -8,7 +8,7 @@ LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` - --> $DIR/issue-106755.rs:15:1 + --> $DIR/issue-106755.rs:17:1 | LL | unsafe impl Send for TestType {} | ------------------------------------------------------ first implementation here @@ -16,7 +16,32 @@ LL | unsafe impl Send for TestType {} LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -error: aborting due to 2 previous errors +error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not + --> $DIR/issue-106755.rs:13:9 + | +LL | impl !Send for TestType {} + | ^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/issue-106755.rs:9:1 + | +LL | struct TestType(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^ + +error[E0366]: `!Send` impls cannot be specialized + --> $DIR/issue-106755.rs:19:1 + | +LL | impl !Send for TestType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `i32` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/issue-106755.rs:9:1 + | +LL | struct TestType(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0119, E0751. +Some errors have detailed explanations: E0119, E0366, E0367, E0751. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/defaultimpl/validation.rs b/tests/ui/specialization/defaultimpl/validation.rs index 4049c4ea14c5b..14771be8982dd 100644 --- a/tests/ui/specialization/defaultimpl/validation.rs +++ b/tests/ui/specialization/defaultimpl/validation.rs @@ -6,12 +6,17 @@ struct Z; default impl S {} //~ ERROR inherent impls cannot be `default` -default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default -//~^ ERROR `S` cannot be sent between threads safely -default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default - //~^ ERROR negative impls cannot be default impls +default unsafe impl Send for S {} +//~^ ERROR impls of auto traits cannot be default + +default impl !Send for Z {} +//~^ ERROR impls of auto traits cannot be default +//~| ERROR negative impls cannot be default impls +//~| ERROR `!Send` impl requires `Z: Send` but the struct it is implemented for does not trait Tr {} -default impl !Tr for S {} //~ ERROR negative impls cannot be default impls + +default impl !Tr for S {} +//~^ ERROR negative impls cannot be default impls fn main() {} diff --git a/tests/ui/specialization/defaultimpl/validation.stderr b/tests/ui/specialization/defaultimpl/validation.stderr index f56f16162a27f..d034386b842f3 100644 --- a/tests/ui/specialization/defaultimpl/validation.stderr +++ b/tests/ui/specialization/defaultimpl/validation.stderr @@ -26,22 +26,20 @@ LL | default unsafe impl Send for S {} | | | default because of this -error[E0277]: `S` cannot be sent between threads safely - --> $DIR/validation.rs:9:1 +error[E0367]: `!Send` impl requires `Z: Send` but the struct it is implemented for does not + --> $DIR/validation.rs:12:1 | -LL | default unsafe impl Send for S {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `S` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `S` - = help: the trait `Send` is implemented for `S` - = help: see issue #48214 -help: add `#![feature(trivial_bounds)]` to the crate attributes to enable +LL | default impl !Send for Z {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ | -LL + #![feature(trivial_bounds)] +note: the implementor must specify the same requirement + --> $DIR/validation.rs:5:1 | +LL | struct Z; + | ^^^^^^^^ error: impls of auto traits cannot be default - --> $DIR/validation.rs:11:15 + --> $DIR/validation.rs:12:15 | LL | default impl !Send for Z {} | ------- ^^^^ auto trait @@ -49,18 +47,18 @@ LL | default impl !Send for Z {} | default because of this error[E0750]: negative impls cannot be default impls - --> $DIR/validation.rs:11:1 + --> $DIR/validation.rs:12:1 | LL | default impl !Send for Z {} | ^^^^^^^ ^ error[E0750]: negative impls cannot be default impls - --> $DIR/validation.rs:15:1 + --> $DIR/validation.rs:19:1 | LL | default impl !Tr for S {} | ^^^^^^^ ^ error: aborting due to 6 previous errors; 1 warning emitted -Some errors have detailed explanations: E0277, E0750. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0367, E0750. +For more information about an error, try `rustc --explain E0367`. diff --git a/tests/ui/specialization/specialization-overlap-negative.rs b/tests/ui/specialization/specialization-overlap-negative.rs index 550d370829539..244f21c7ba905 100644 --- a/tests/ui/specialization/specialization-overlap-negative.rs +++ b/tests/ui/specialization/specialization-overlap-negative.rs @@ -6,6 +6,8 @@ trait MyTrait {} struct TestType(::std::marker::PhantomData); unsafe impl Send for TestType {} -impl !Send for TestType {} //~ ERROR E0751 +impl !Send for TestType {} +//~^ ERROR found both positive and negative implementation of trait `Send` for type `TestType<_>` +//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not fn main() {} diff --git a/tests/ui/specialization/specialization-overlap-negative.stderr b/tests/ui/specialization/specialization-overlap-negative.stderr index a8e99953e2b65..4874e897726fc 100644 --- a/tests/ui/specialization/specialization-overlap-negative.stderr +++ b/tests/ui/specialization/specialization-overlap-negative.stderr @@ -16,6 +16,19 @@ LL | unsafe impl Send for TestType {} LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to 1 previous error; 1 warning emitted +error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not + --> $DIR/specialization-overlap-negative.rs:9:9 + | +LL | impl !Send for TestType {} + | ^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/specialization-overlap-negative.rs:6:1 + | +LL | struct TestType(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0751`. +Some errors have detailed explanations: E0367, E0751. +For more information about an error, try `rustc --explain E0367`. From 05a80608b36f71f49e6cc8d586f54c023264ac12 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Feb 2025 02:43:12 +0000 Subject: [PATCH 31/40] Make rustdoc tests use always applicable negative auto impls --- .../src/check/always_applicable.rs | 4 +- tests/rustdoc/impl-parts-crosscrate.rs | 2 +- tests/rustdoc/impl-parts.rs | 2 +- .../coherence-overlap-negative-impls.rs | 42 --------------- .../coherence-overlap-negative-impls.stderr | 16 ------ .../negated-auto-traits-validity-error.rs | 22 ++++++++ .../negated-auto-traits-validity-error.stderr | 54 +++++++++++++++++++ .../negated-auto-traits-validity.rs | 22 ++++++++ 8 files changed, 102 insertions(+), 62 deletions(-) delete mode 100644 tests/ui/coherence/coherence-overlap-negative-impls.rs delete mode 100644 tests/ui/coherence/coherence-overlap-negative-impls.stderr create mode 100644 tests/ui/traits/negative-impls/negated-auto-traits-validity-error.rs create mode 100644 tests/ui/traits/negative-impls/negated-auto-traits-validity-error.stderr create mode 100644 tests/ui/traits/negative-impls/negated-auto-traits-validity.rs diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 64377ffa34761..ba5b61d3fce0b 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -140,7 +140,7 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>( return Ok(()); }; - let drop_impl_span = tcx.def_span(impl_def_id); + let impl_span = tcx.def_span(impl_def_id); let item_span = tcx.def_span(adt_def_id); let self_descr = tcx.def_descr(adt_def_id); let polarity = match tcx.impl_polarity(impl_def_id) { @@ -151,7 +151,7 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>( .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait")); let mut err = struct_span_code_err!( tcx.dcx(), - drop_impl_span, + impl_span, E0366, "`{polarity}{trait_name}` impls cannot be specialized", ); diff --git a/tests/rustdoc/impl-parts-crosscrate.rs b/tests/rustdoc/impl-parts-crosscrate.rs index 49752ab75d512..631c8bb3eb318 100644 --- a/tests/rustdoc/impl-parts-crosscrate.rs +++ b/tests/rustdoc/impl-parts-crosscrate.rs @@ -5,7 +5,7 @@ extern crate rustdoc_impl_parts_crosscrate; -pub struct Bar { t: T } +pub struct Bar { t: T } // The output file is html embedded in javascript, so the html tags // aren't stripped by the processing script and we can't check for the diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl-parts.rs index 820f51008a40c..4f281bfd63c83 100644 --- a/tests/rustdoc/impl-parts.rs +++ b/tests/rustdoc/impl-parts.rs @@ -3,7 +3,7 @@ pub auto trait AnAutoTrait {} -pub struct Foo { field: T } +pub struct Foo { field: T } //@ has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !AnAutoTrait for Foowhere T: Sync + Clone," diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.rs b/tests/ui/coherence/coherence-overlap-negative-impls.rs deleted file mode 100644 index ba90a37cb2aab..0000000000000 --- a/tests/ui/coherence/coherence-overlap-negative-impls.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Should fail. The `0` and `1` impls overlap, violating coherence. Eg, with -// `T = Test, F = ()`, all bounds are true, making both impls applicable. -// `Test: Fold`, `Test: Fold<()>` are true because of `2`. -// `Is: NotNil` is true because of `auto trait` and lack of negative impl. - -#![feature(negative_impls)] -#![feature(auto_traits)] - -struct Nil; -struct Cons(H); -struct Test; - -trait Fold {} - -impl Fold for Cons -// 0 -where - T: Fold, -{ -} - -impl Fold for Cons -// 1 -where - T: Fold, - private::Is: private::NotNil, -{ -} - -impl Fold for Test {} // 2 - -mod private { - use crate::Nil; - - pub struct Is(T); - pub auto trait NotNil {} - - impl !NotNil for Is {} - //~^ ERROR `!NotNil` impls cannot be specialized -} - -fn main() {} diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.stderr b/tests/ui/coherence/coherence-overlap-negative-impls.stderr deleted file mode 100644 index fe22cf61b753c..0000000000000 --- a/tests/ui/coherence/coherence-overlap-negative-impls.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0366]: `!NotNil` impls cannot be specialized - --> $DIR/coherence-overlap-negative-impls.rs:38:5 - | -LL | impl !NotNil for Is {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Nil` is not a generic parameter -note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/coherence-overlap-negative-impls.rs:35:5 - | -LL | pub struct Is(T); - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0366`. diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.rs b/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.rs new file mode 100644 index 0000000000000..cd675a5efd162 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.rs @@ -0,0 +1,22 @@ +#![feature(auto_traits, negative_impls)] + +auto trait Foo {} + +struct AdditionalLt<'a, T>(&'a (), T); +impl<'a, T: 'a> !Foo for AdditionalLt<'a, T> {} +//~^ ERROR `!Foo` impl requires `T: 'a` but the struct it is implemented for does not + +struct AdditionalBound(T); +trait Bound {} +impl !Foo for AdditionalBound {} +//~^ ERROR `!Foo` impl requires `T: Bound` but the struct it is implemented for does not + +struct TwoParam(T, U); +impl !Foo for TwoParam {} +//~^ ERROR `!Foo` impls cannot be specialized + +struct ConcreteParam(T); +impl !Foo for ConcreteParam {} +//~^ ERROR `!Foo` impls cannot be specialized + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.stderr new file mode 100644 index 0000000000000..ef783e9015592 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-validity-error.stderr @@ -0,0 +1,54 @@ +error[E0367]: `!Foo` impl requires `T: 'a` but the struct it is implemented for does not + --> $DIR/negated-auto-traits-validity-error.rs:6:13 + | +LL | impl<'a, T: 'a> !Foo for AdditionalLt<'a, T> {} + | ^^ + | +note: the implementor must specify the same requirement + --> $DIR/negated-auto-traits-validity-error.rs:5:1 + | +LL | struct AdditionalLt<'a, T>(&'a (), T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0367]: `!Foo` impl requires `T: Bound` but the struct it is implemented for does not + --> $DIR/negated-auto-traits-validity-error.rs:11:9 + | +LL | impl !Foo for AdditionalBound {} + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/negated-auto-traits-validity-error.rs:9:1 + | +LL | struct AdditionalBound(T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0366]: `!Foo` impls cannot be specialized + --> $DIR/negated-auto-traits-validity-error.rs:15:1 + | +LL | impl !Foo for TwoParam {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `T` is mentioned multiple times +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/negated-auto-traits-validity-error.rs:14:1 + | +LL | struct TwoParam(T, U); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0366]: `!Foo` impls cannot be specialized + --> $DIR/negated-auto-traits-validity-error.rs:19:1 + | +LL | impl !Foo for ConcreteParam {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `i32` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/negated-auto-traits-validity-error.rs:18:1 + | +LL | struct ConcreteParam(T); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0366, E0367. +For more information about an error, try `rustc --explain E0366`. diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-validity.rs b/tests/ui/traits/negative-impls/negated-auto-traits-validity.rs new file mode 100644 index 0000000000000..76996b5593e60 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-validity.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(auto_traits, negative_impls)] + +auto trait Foo {} +auto trait Bar {} + +struct NeedsOutlives<'a, T>(&'a T); + +impl<'a, T: 'a> !Foo for NeedsOutlives<'a, T> {} + +// Leaving out the lifetime bound +impl<'a, T> !Bar for NeedsOutlives<'a, T> {} + +struct NeedsSend(T); + +impl !Foo for NeedsSend {} + +// Leaving off the trait bound +impl !Bar for NeedsSend {} + +fn main() {} From 7923031e7ef449aa0b1ed5ed2af9e83fc434ceda Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Mar 2025 01:35:02 -0500 Subject: [PATCH 32/40] Update `compiler-builtins` to 0.1.151 This enables `f16` builtins for loongarch [1] and adds support for Cygwin [2]. [1]: https://github.com/rust-lang/compiler-builtins/pull/770 [2]: https://github.com/rust-lang/compiler-builtins/pull/774 --- ...029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch | 4 ++-- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index d8db7d63f2dda..c2027863b00b1 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/Cargo.lock b/library/Cargo.lock index 37b10649ced4b..74d9f00df21bd 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.150" +version = "0.1.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c42734e0ccf0d9f953165770593a75306f0b24dda1aa03f115c70748726dbca" +checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 9cf9e98e89ee4..4cb8350125686 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.9.0", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 8e4dd0f2bf480..288732ac1467c 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.150" } +compiler_builtins = { version = "=0.1.151" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From e0b75776c3265fdb9dead021e565c2fda906ed88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 26 Feb 2025 15:45:36 +0000 Subject: [PATCH 33/40] linux x64: default to `-znostart-stop-gc` This will help stabilization of lld. --- compiler/rustc_codegen_ssa/src/back/link.rs | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a170b2e3b6a56..3407117a06e3b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3382,6 +3382,35 @@ fn add_lld_args( // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { cmd.cc_arg("-fuse-ld=lld"); + + // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some + // section garbage-collection features. For example, the somewhat popular `linkme` crate and + // its dependents rely in practice on this difference: when using lld, they need `-z + // nostart-stop-gc` to prevent encapsulation symbols and sections from being + // garbage-collected. + // + // More information about all this can be found in: + // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order + // - https://lld.llvm.org/ELF/start-stop-gc + // + // So when using lld, we restore, for now, the traditional behavior to help migration, but + // will remove it in the future. + // Since this only disables an optimization, it shouldn't create issues, but is in theory + // slightly suboptimal. However, it: + // - doesn't have any visible impact on our benchmarks + // - reduces the need to disable lld for the crates that depend on this + // + // Note that lld can detect some cases where this difference is relied on, and emits a + // dedicated error to add this link arg. We could make use of this error to emit an FCW. As + // of writing this, we don't do it, because lld is already enabled by default on nightly + // without this mitigation: no working project would see the FCW, so we do this to help + // stabilization. + // + // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the + // future. + if sess.target.llvm_target == "x86_64-unknown-linux-gnu" { + cmd.link_arg("-znostart-stop-gc"); + } } if !flavor.is_gnu() { From 056ec72efe71f328c40fcce63f070b3b84fbdde1 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 5 Mar 2025 12:05:19 +0300 Subject: [PATCH 34/40] trim channel value in `get_closest_merge_commit` Signed-off-by: onur-ozkan --- src/build_helper/src/git.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 3ef9c7ac35e9d..9f778a2fd7742 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -129,7 +129,7 @@ pub fn get_closest_merge_commit( git.current_dir(git_dir); } - let channel = include_str!("../../ci/channel"); + let channel = include_str!("../../ci/channel").trim(); let merge_base = { if CiEnv::is_ci() && From 36efaf8437fd3926868293c87fa6cffc6f309bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 5 Mar 2025 10:54:11 +0100 Subject: [PATCH 35/40] normalize away `-Wlinker-messages` wrappers from `rust-lld` rmake test --- tests/run-make/rust-lld/rmake.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs index e5ae943538842..35f716c24c71a 100644 --- a/tests/run-make/rust-lld/rmake.rs +++ b/tests/run-make/rust-lld/rmake.rs @@ -60,7 +60,8 @@ fn main() { } fn find_lld_version_in_logs(stderr: String) -> bool { - let lld_version_re = - Regex::new(r"^warning: linker std(out|err): LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); + // Strip the `-Wlinker-messages` wrappers prefixing the linker output. + let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, ""); + let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); stderr.lines().any(|line| lld_version_re.is_match(line.trim())) } From 70c4a31f6b17a8402eb3459ae7c607187b4e2771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 25 Feb 2025 13:43:25 +0100 Subject: [PATCH 36/40] Update bootstrap to edition 2024 --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/bin/sccache-plus-cl.rs | 9 +++- src/bootstrap/src/core/build_steps/format.rs | 2 +- src/bootstrap/src/utils/cc_detect/tests.rs | 56 +++++++++++++------- src/bootstrap/src/utils/helpers.rs | 2 +- src/bootstrap/src/utils/job.rs | 4 +- 6 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2c1d85b01e6af..2ea2596088fd5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2021" +edition = "2024" build = "build.rs" default-run = "bootstrap" diff --git a/src/bootstrap/src/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs index 6e87d4222e863..c161d69d5f73b 100644 --- a/src/bootstrap/src/bin/sccache-plus-cl.rs +++ b/src/bootstrap/src/bin/sccache-plus-cl.rs @@ -4,8 +4,13 @@ use std::process::{self, Command}; fn main() { let target = env::var("SCCACHE_TARGET").unwrap(); // Locate the actual compiler that we're invoking - env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); - env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + + // SAFETY: we're in main, there are no other threads + unsafe { + env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); + env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + } + let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .out_dir("/") diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index c7eafadee2df3..9817e47baa101 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -27,7 +27,7 @@ fn rustfmt( rustfmt: &Path, paths: &[PathBuf], check: bool, -) -> impl FnMut(bool) -> RustfmtStatus { +) -> impl FnMut(bool) -> RustfmtStatus + use<> { let mut cmd = Command::new(rustfmt); // Avoid the submodule config paths from coming into play. We only allow a single global config // for the workspace for now. diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 006dfe7e5d7b3..c97529cbe9eb4 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -9,20 +9,24 @@ use crate::{Build, Config, Flags}; fn test_cc2ar_env_specific() { let triple = "x86_64-unknown-linux-gnu"; let key = "AR_x86_64_unknown_linux_gnu"; - env::set_var(key, "custom-ar"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var(key, "custom-ar") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); let result = cc2ar(cc, target, default_ar); - env::remove_var(key); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var(key) }; assert_eq!(result, Some(PathBuf::from("custom-ar"))); } #[test] fn test_cc2ar_musl() { let triple = "x86_64-unknown-linux-musl"; - env::remove_var("AR_x86_64_unknown_linux_musl"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -33,8 +37,10 @@ fn test_cc2ar_musl() { #[test] fn test_cc2ar_openbsd() { let triple = "x86_64-unknown-openbsd"; - env::remove_var("AR_x86_64_unknown_openbsd"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_openbsd") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/cc"); let default_ar = PathBuf::from("default-ar"); @@ -45,8 +51,10 @@ fn test_cc2ar_openbsd() { #[test] fn test_cc2ar_vxworks() { let triple = "armv7-wrs-vxworks"; - env::remove_var("AR_armv7_wrs_vxworks"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_armv7_wrs_vxworks") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -57,8 +65,10 @@ fn test_cc2ar_vxworks() { #[test] fn test_cc2ar_nto_i586() { let triple = "i586-unknown-nto-something"; - env::remove_var("AR_i586_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_i586_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -69,8 +79,10 @@ fn test_cc2ar_nto_i586() { #[test] fn test_cc2ar_nto_aarch64() { let triple = "aarch64-unknown-nto-something"; - env::remove_var("AR_aarch64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_aarch64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -81,8 +93,10 @@ fn test_cc2ar_nto_aarch64() { #[test] fn test_cc2ar_nto_x86_64() { let triple = "x86_64-unknown-nto-something"; - env::remove_var("AR_x86_64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -94,8 +108,10 @@ fn test_cc2ar_nto_x86_64() { #[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] fn test_cc2ar_nto_unknown() { let triple = "powerpc-unknown-nto-something"; - env::remove_var("AR_powerpc_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_powerpc_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -177,7 +193,8 @@ fn test_default_compiler_wasi() { let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); - env::set_var("WASI_SDK_PATH", &wasi_sdk); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) }; let mut cfg = cc::Build::new(); if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { let expected = { @@ -190,7 +207,10 @@ fn test_default_compiler_wasi() { "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set" ); } - env::remove_var("WASI_SDK_PATH"); + // SAFETY: bootstrap tests run on a single thread + unsafe { + env::remove_var("WASI_SDK_PATH"); + } } #[test] diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 7ad308cd06728..89d93a29acbca 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -286,7 +286,7 @@ pub fn output(cmd: &mut Command) -> String { /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap. #[track_caller] -pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> { let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { Ok(child) => child, Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 10efed130d624..2ad5aa8e798dc 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -7,7 +7,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {} #[cfg(all(unix, not(target_os = "haiku")))] pub unsafe fn setup(build: &mut crate::Build) { if build.config.low_priority { - libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + unsafe { + libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + } } } From 3dbf3dc1e187d1c0654870597f85fdff4f5a640f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 5 Mar 2025 12:27:10 +0100 Subject: [PATCH 37/40] Increase the max. custom try jobs requested to `20` --- src/ci/citool/src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index cef92e998da1a..6a5643ab37a2e 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -180,6 +180,10 @@ fn yaml_map_to_json(map: &BTreeMap) -> BTreeMap (db.pr_jobs.clone(), "PR", &db.envs.pr_env), RunType::TryJob { custom_jobs } => { let jobs = if let Some(custom_jobs) = custom_jobs { - if custom_jobs.len() > 10 { + if custom_jobs.len() > MAX_TRY_JOBS_COUNT { return Err(anyhow::anyhow!( - "It is only possible to schedule up to 10 custom jobs, received {} custom jobs", + "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs", custom_jobs.len() )); } From cb7d687e96151adc81c55fc48734497a2b48e79c Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 19 Jan 2025 23:30:58 +0800 Subject: [PATCH 38/40] Implement `&pin const self` and `&pin mut self` sugars --- compiler/rustc_ast/src/ast.rs | 21 ++++- compiler/rustc_ast_pretty/src/pprust/state.rs | 7 ++ compiler/rustc_parse/src/parser/item.rs | 45 ++++++++++ src/tools/rustfmt/src/items.rs | 27 ++++++ src/tools/rustfmt/tests/source/pin_sugar.rs | 10 +++ src/tools/rustfmt/tests/target/pin_sugar.rs | 9 ++ tests/pretty/pin-ergonomics.rs | 24 +++++ .../async-await/pin-ergonomics/sugar-self.rs | 46 ++++++++++ .../feature-gate-pin_ergonomics.rs | 40 ++++++++- .../feature-gate-pin_ergonomics.stderr | 88 +++++++++++++++++-- 10 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 tests/pretty/pin-ergonomics.rs create mode 100644 tests/ui/async-await/pin-ergonomics/sugar-self.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fb6b36e1a09da..11fc409cf4333 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2641,6 +2641,8 @@ pub enum SelfKind { Value(Mutability), /// `&'lt self`, `&'lt mut self` Region(Option, Mutability), + /// `&'lt pin const self`, `&'lt pin mut self` + Pinned(Option, Mutability), /// `self: TYPE`, `mut self: TYPE` Explicit(P, Mutability), } @@ -2650,6 +2652,8 @@ impl SelfKind { match self { SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(), SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()), + SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()), + SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()), SelfKind::Value(_) | SelfKind::Explicit(_, _) => { unreachable!("if we had an explicit self, we wouldn't be here") } @@ -2666,11 +2670,13 @@ impl Param { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Ref(lt, MutTy { ref ty, mutbl }) - | TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) + TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + } + TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl))) } _ => Some(respan( self.pat.span.to(self.ty.span), @@ -2712,6 +2718,15 @@ impl Param { tokens: None, }), ), + SelfKind::Pinned(lt, mutbl) => ( + mutbl, + P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }), + span, + tokens: None, + }), + ), }; Param { attrs, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index d747237f76dbc..01fc272a45897 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1783,6 +1783,13 @@ impl<'a> State<'a> { self.print_mutability(*m, false); self.word("self") } + SelfKind::Pinned(lt, m) => { + self.word("&"); + self.print_opt_lifetime(lt); + self.word("pin "); + self.print_mutability(*m, true); + self.word("self") + } SelfKind::Explicit(typ, m) => { self.print_mutability(*m, false); self.word("self"); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f642a7ac1fdd..68a16a1c66bb4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2959,9 +2959,20 @@ impl<'a> Parser<'a> { this.is_keyword_ahead(n, &[kw::SelfLower]) && this.look_ahead(n + 1, |t| t != &token::PathSep) }; + // Is `pin const self` `n` tokens ahead? + let is_isolated_pin_const_self = |this: &Self, n| { + this.look_ahead(n, |token| token.is_ident_named(sym::pin)) + && this.is_keyword_ahead(n + 1, &[kw::Const]) + && is_isolated_self(this, n + 2) + }; // Is `mut self` `n` tokens ahead? let is_isolated_mut_self = |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1); + // Is `pin mut self` `n` tokens ahead? + let is_isolated_pin_mut_self = |this: &Self, n| { + this.look_ahead(n, |token| token.is_ident_named(sym::pin)) + && is_isolated_mut_self(this, n + 1) + }; // Parse `self` or `self: TYPE`. We already know the current token is `self`. let parse_self_possibly_typed = |this: &mut Self, m| { let eself_ident = expect_self_ident(this); @@ -3021,6 +3032,20 @@ impl<'a> Parser<'a> { self.bump(); self.bump(); SelfKind::Region(None, Mutability::Mut) + } else if is_isolated_pin_const_self(self, 1) { + // `&pin const self` + self.bump(); // & + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // const + SelfKind::Pinned(None, Mutability::Not) + } else if is_isolated_pin_mut_self(self, 1) { + // `&pin mut self` + self.bump(); // & + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // mut + SelfKind::Pinned(None, Mutability::Mut) } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { // `&'lt self` self.bump(); @@ -3032,6 +3057,26 @@ impl<'a> Parser<'a> { let lt = self.expect_lifetime(); self.bump(); SelfKind::Region(Some(lt), Mutability::Mut) + } else if self.look_ahead(1, |t| t.is_lifetime()) + && is_isolated_pin_const_self(self, 2) + { + // `&'lt pin const self` + self.bump(); // & + let lt = self.expect_lifetime(); + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // const + SelfKind::Pinned(Some(lt), Mutability::Not) + } else if self.look_ahead(1, |t| t.is_lifetime()) + && is_isolated_pin_mut_self(self, 2) + { + // `&'lt pin mut self` + self.bump(); // & + let lt = self.expect_lifetime(); + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // mut + SelfKind::Pinned(Some(lt), Mutability::Mut) } else { // `¬_self` return Ok(None); diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 457d0afe3b5b7..e9e7c4ed8f9c9 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2395,6 +2395,33 @@ fn rewrite_explicit_self( )?), } } + ast::SelfKind::Pinned(lt, m) => { + let mut_str = m.ptr_str(); + match lt { + Some(ref l) => { + let lifetime_str = l.rewrite_result( + context, + Shape::legacy(context.config.max_width(), Indent::empty()), + )?; + Ok(combine_strs_with_missing_comments( + context, + param_attrs, + &format!("&{lifetime_str} pin {mut_str} self"), + span, + shape, + !has_multiple_attr_lines, + )?) + } + None => Ok(combine_strs_with_missing_comments( + context, + param_attrs, + &format!("&pin {mut_str} self"), + span, + shape, + !has_multiple_attr_lines, + )?), + } + } ast::SelfKind::Explicit(ref ty, mutability) => { let type_str = ty.rewrite_result( context, diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs index 0eb3c0770c482..370dfbc196aea 100644 --- a/src/tools/rustfmt/tests/source/pin_sugar.rs +++ b/src/tools/rustfmt/tests/source/pin_sugar.rs @@ -8,3 +8,13 @@ fn g<'a>(x: & 'a pin const i32) {} fn h<'a>(x: & 'a pin mut i32) {} fn i(x: &pin mut i32) {} + +struct Foo; + +impl Foo { + fn f(&pin const self) {} + fn g<'a>(& 'a pin const self) {} + fn h<'a>(& 'a pin +mut self) {} + fn i(&pin mut self) {} +} diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs index c9fa883e238fd..7d04efb1b3266 100644 --- a/src/tools/rustfmt/tests/target/pin_sugar.rs +++ b/src/tools/rustfmt/tests/target/pin_sugar.rs @@ -7,3 +7,12 @@ fn f(x: &pin const i32) {} fn g<'a>(x: &'a pin const i32) {} fn h<'a>(x: &'a pin mut i32) {} fn i(x: &pin mut i32) {} + +struct Foo; + +impl Foo { + fn f(&pin const self) {} + fn g<'a>(&'a pin const self) {} + fn h<'a>(&'a pin mut self) {} + fn i(&pin mut self) {} +} diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs new file mode 100644 index 0000000000000..47ffc97b1183f --- /dev/null +++ b/tests/pretty/pin-ergonomics.rs @@ -0,0 +1,24 @@ +//@ pp-exact + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +struct Foo; + +impl Foo { + fn baz(&pin mut self) {} + + fn baz_const(&pin const self) {} + + fn baz_lt<'a>(&'a pin mut self) {} + + fn baz_const_lt(&'_ pin const self) {} +} + +fn foo(_: &pin mut Foo) {} +fn foo_lt<'a>(_: &'a pin mut Foo) {} + +fn foo_const(_: &pin const Foo) {} +fn foo_const_lt(_: &'_ pin const Foo) {} + +fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/sugar-self.rs b/tests/ui/async-await/pin-ergonomics/sugar-self.rs new file mode 100644 index 0000000000000..3d71b54b1aec3 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/sugar-self.rs @@ -0,0 +1,46 @@ +//@ check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure we can handle `&pin mut self` and `&pin const self` as sugar for +// `self: Pin<&mut Self>` and `self: Pin<&Self>`. + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn baz(&pin mut self) {} + + fn baz_const(&pin const self) {} + + fn baz_lt<'a>(&'a pin mut self) {} + + fn baz_const_lt(&'_ pin const self) {} +} + +fn foo(_: &pin mut Foo) {} + +fn foo_const(_: &pin const Foo) {} + +fn bar(x: &pin mut Foo) { + // For the calls below to work we need to automatically reborrow, + // as if the user had written `foo(x.as_mut())`. + foo(x); + foo(x); + + Foo::baz(x); + Foo::baz(x); + + // make sure we can reborrow &mut as &. + foo_const(x); + Foo::baz_const(x); + + let x: &pin const _ = Pin::new(&Foo); + + foo_const(x); // make sure reborrowing from & to & works. + foo_const(x); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 4624faf1e53cf..663a83a665c48 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -7,9 +7,13 @@ struct Foo; impl Foo { fn foo(self: Pin<&mut Self>) { } + fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental + fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental } -fn foo(x: Pin<&mut Foo>) { +fn foo(mut x: Pin<&mut Foo>) { + Foo::foo_sugar(x.as_mut()); + Foo::foo_sugar_const(x.as_ref()); let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental } @@ -27,4 +31,38 @@ fn baz(mut x: Pin<&mut Foo>) { fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental +#[cfg(any())] +mod not_compiled { + use std::pin::Pin; + + struct Foo; + + impl Foo { + fn foo(self: Pin<&mut Self>) { + } + fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental + fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental + } + + fn foo(mut x: Pin<&mut Foo>) { + Foo::foo_sugar(x.as_mut()); + Foo::foo_sugar_const(x.as_ref()); + let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental + } + + fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental + + fn bar(x: Pin<&mut Foo>) { + foo(x); + foo(x); + } + + fn baz(mut x: Pin<&mut Foo>) { + x.foo(); + x.foo(); + } + + fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental +} + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index dd93a7be1ada1..8ed7543d86e3d 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -1,5 +1,25 @@ error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:13:14 + --> $DIR/feature-gate-pin_ergonomics.rs:10:19 + | +LL | fn foo_sugar(&pin mut self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:11:25 + | +LL | fn foo_sugar_const(&pin const self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:17:14 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -9,7 +29,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:16:18 + --> $DIR/feature-gate-pin_ergonomics.rs:20:18 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -19,7 +39,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:28:18 + --> $DIR/feature-gate-pin_ergonomics.rs:32:18 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -28,8 +48,58 @@ LL | fn baz_sugar(_: &pin const Foo) {} = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:43:23 + | +LL | fn foo_sugar(&pin mut self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:44:29 + | +LL | fn foo_sugar_const(&pin const self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:50:18 + | +LL | let _y: &pin mut Foo = x; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:53:22 + | +LL | fn foo_sugar(_: &pin mut Foo) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:65:22 + | +LL | fn baz_sugar(_: &pin const Foo) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:20:9 + --> $DIR/feature-gate-pin_ergonomics.rs:24:9 | LL | fn bar(x: Pin<&mut Foo>) { | - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -39,15 +109,15 @@ LL | foo(x); | ^ value used here after move | note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:12:11 + --> $DIR/feature-gate-pin_ergonomics.rs:14:15 | -LL | fn foo(x: Pin<&mut Foo>) { - | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value +LL | fn foo(mut x: Pin<&mut Foo>) { + | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:25:5 + --> $DIR/feature-gate-pin_ergonomics.rs:29:5 | LL | fn baz(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -66,7 +136,7 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 5 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0382, E0658. For more information about an error, try `rustc --explain E0382`. From 52cd8746bab900aa38210d24c62352170b9f51f8 Mon Sep 17 00:00:00 2001 From: Frank King Date: Wed, 5 Mar 2025 22:13:22 +0800 Subject: [PATCH 39/40] Simplify `parse_self_param` --- compiler/rustc_parse/src/parser/item.rs | 63 ++++++++----------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 68a16a1c66bb4..c3b1956ad2e82 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2954,6 +2954,8 @@ impl<'a> Parser<'a> { } _ => unreachable!(), }; + // is lifetime `n` tokens ahead? + let is_lifetime = |this: &Self, n| this.look_ahead(n, |t| t.is_lifetime()); // Is `self` `n` tokens ahead? let is_isolated_self = |this: &Self, n| { this.is_keyword_ahead(n, &[kw::SelfLower]) @@ -3023,60 +3025,35 @@ impl<'a> Parser<'a> { let eself_lo = self.token.span; let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind { token::And => { - let eself = if is_isolated_self(self, 1) { - // `&self` - self.bump(); - SelfKind::Region(None, Mutability::Not) - } else if is_isolated_mut_self(self, 1) { - // `&mut self` - self.bump(); - self.bump(); - SelfKind::Region(None, Mutability::Mut) - } else if is_isolated_pin_const_self(self, 1) { - // `&pin const self` + let has_lifetime = is_lifetime(self, 1); + let skip_lifetime_count = has_lifetime as usize; + let eself = if is_isolated_self(self, skip_lifetime_count + 1) { + // `&{'lt} self` self.bump(); // & - self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); - self.bump(); // pin - self.bump(); // const - SelfKind::Pinned(None, Mutability::Not) - } else if is_isolated_pin_mut_self(self, 1) { - // `&pin mut self` + let lifetime = has_lifetime.then(|| self.expect_lifetime()); + SelfKind::Region(lifetime, Mutability::Not) + } else if is_isolated_mut_self(self, skip_lifetime_count + 1) { + // `&{'lt} mut self` self.bump(); // & - self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); - self.bump(); // pin + let lifetime = has_lifetime.then(|| self.expect_lifetime()); self.bump(); // mut - SelfKind::Pinned(None, Mutability::Mut) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { - // `&'lt self` - self.bump(); - let lt = self.expect_lifetime(); - SelfKind::Region(Some(lt), Mutability::Not) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { - // `&'lt mut self` - self.bump(); - let lt = self.expect_lifetime(); - self.bump(); - SelfKind::Region(Some(lt), Mutability::Mut) - } else if self.look_ahead(1, |t| t.is_lifetime()) - && is_isolated_pin_const_self(self, 2) - { - // `&'lt pin const self` + SelfKind::Region(lifetime, Mutability::Mut) + } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) { + // `&{'lt} pin const self` self.bump(); // & - let lt = self.expect_lifetime(); + let lifetime = has_lifetime.then(|| self.expect_lifetime()); self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); self.bump(); // pin self.bump(); // const - SelfKind::Pinned(Some(lt), Mutability::Not) - } else if self.look_ahead(1, |t| t.is_lifetime()) - && is_isolated_pin_mut_self(self, 2) - { - // `&'lt pin mut self` + SelfKind::Pinned(lifetime, Mutability::Not) + } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) { + // `&{'lt} pin mut self` self.bump(); // & - let lt = self.expect_lifetime(); + let lifetime = has_lifetime.then(|| self.expect_lifetime()); self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); self.bump(); // pin self.bump(); // mut - SelfKind::Pinned(Some(lt), Mutability::Mut) + SelfKind::Pinned(lifetime, Mutability::Mut) } else { // `¬_self` return Ok(None); From 50d0f992acf3e7b4f0801a6a749e379a616a71d8 Mon Sep 17 00:00:00 2001 From: Frank King Date: Wed, 5 Mar 2025 22:35:50 +0800 Subject: [PATCH 40/40] Simplify `rewrite_explicit_self` --- src/tools/rustfmt/src/items.rs | 98 +++++++++++----------------------- 1 file changed, 31 insertions(+), 67 deletions(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e9e7c4ed8f9c9..3fb3284e3d7fd 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2359,6 +2359,21 @@ impl Rewrite for ast::Param { } } +fn rewrite_opt_lifetime( + context: &RewriteContext<'_>, + lifetime: Option, +) -> RewriteResult { + let Some(l) = lifetime else { + return Ok(String::new()); + }; + let mut result = l.rewrite_result( + context, + Shape::legacy(context.config.max_width(), Indent::empty()), + )?; + result.push(' '); + Ok(result) +} + fn rewrite_explicit_self( context: &RewriteContext<'_>, explicit_self: &ast::ExplicitSelf, @@ -2367,85 +2382,34 @@ fn rewrite_explicit_self( shape: Shape, has_multiple_attr_lines: bool, ) -> RewriteResult { - match explicit_self.node { + let self_str = match explicit_self.node { ast::SelfKind::Region(lt, m) => { let mut_str = format_mutability(m); - match lt { - Some(ref l) => { - let lifetime_str = l.rewrite_result( - context, - Shape::legacy(context.config.max_width(), Indent::empty()), - )?; - Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&{lifetime_str} {mut_str}self"), - span, - shape, - !has_multiple_attr_lines, - )?) - } - None => Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&{mut_str}self"), - span, - shape, - !has_multiple_attr_lines, - )?), - } + let lifetime_str = rewrite_opt_lifetime(context, lt)?; + format!("&{lifetime_str}{mut_str}self") } ast::SelfKind::Pinned(lt, m) => { let mut_str = m.ptr_str(); - match lt { - Some(ref l) => { - let lifetime_str = l.rewrite_result( - context, - Shape::legacy(context.config.max_width(), Indent::empty()), - )?; - Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&{lifetime_str} pin {mut_str} self"), - span, - shape, - !has_multiple_attr_lines, - )?) - } - None => Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&pin {mut_str} self"), - span, - shape, - !has_multiple_attr_lines, - )?), - } + let lifetime_str = rewrite_opt_lifetime(context, lt)?; + format!("&{lifetime_str}pin {mut_str} self") } ast::SelfKind::Explicit(ref ty, mutability) => { let type_str = ty.rewrite_result( context, Shape::legacy(context.config.max_width(), Indent::empty()), )?; - - Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("{}self: {}", format_mutability(mutability), type_str), - span, - shape, - !has_multiple_attr_lines, - )?) + format!("{}self: {}", format_mutability(mutability), type_str) } - ast::SelfKind::Value(mutability) => Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("{}self", format_mutability(mutability)), - span, - shape, - !has_multiple_attr_lines, - )?), - } + ast::SelfKind::Value(mutability) => format!("{}self", format_mutability(mutability)), + }; + Ok(combine_strs_with_missing_comments( + context, + param_attrs, + &self_str, + span, + shape, + !has_multiple_attr_lines, + )?) } pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {