From 6c87448b57890eabd11103fcb2ab8f5e687a02cc Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 21 Jun 2023 20:49:18 +0200 Subject: [PATCH 01/17] optimize Cstr/EscapeAscii display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit old: ascii::bench_ascii_escape_display_mixed 17.97µs/iter +/- 204.00ns ascii::bench_ascii_escape_display_no_escape 545.00ns/iter +/- 6.00ns new: ascii::bench_ascii_escape_display_mixed 4.99µs/iter +/- 56.00ns ascii::bench_ascii_escape_display_no_escape 91.00ns/iter +/- 1.00ns --- library/core/benches/ascii.rs | 28 ++++++++++++++++ library/core/src/ascii.rs | 11 ++++++ library/core/src/iter/adapters/flatten.rs | 8 +++++ library/core/src/iter/adapters/fuse.rs | 4 +++ library/core/src/iter/adapters/map.rs | 4 +++ library/core/src/slice/ascii.rs | 41 ++++++++++++++++++++++- library/core/tests/ascii.rs | 10 ++++++ 7 files changed, 105 insertions(+), 1 deletion(-) diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index 64938745a4a16..71ec9fed2fe75 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -63,6 +63,7 @@ macro_rules! benches { } } +use std::fmt::Write; use test::black_box; use test::Bencher; @@ -351,3 +352,30 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, ]; + +const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; + +#[bench] +fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = ASCII_PATH.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} + +#[bench] +fn bench_ascii_escape_display_mixed(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = RUST_INCANTATION.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index ef8e4d098ed95..02867789b79dd 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -96,6 +96,17 @@ pub fn escape_default(c: u8) -> EscapeDefault { EscapeDefault(escape::EscapeIterInner::new(data, range)) } +impl EscapeDefault { + pub(crate) fn empty() -> Self { + let data = [Char::Null; 4]; + EscapeDefault(escape::EscapeIterInner::new(data, 0..0)) + } + + pub(crate) fn as_str(&self) -> &str { + self.0.as_str() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for EscapeDefault { type Item = u8; diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 2568aaf34f3fb..f3992b500adf8 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -18,6 +18,14 @@ impl U> FlatMap { pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } + + pub(crate) fn into_parts(self) -> (Option, Option, Option) { + ( + self.inner.frontiter, + self.inner.iter.into_inner().map(Map::into_inner), + self.inner.backiter, + ) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index b1fa4f92117b1..e38234eae4990 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -24,6 +24,10 @@ impl Fuse { pub(in crate::iter) fn new(iter: I) -> Fuse { Fuse { iter: Some(iter) } } + + pub(crate) fn into_inner(self) -> Option { + self.iter + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 31d02a4da6ea5..2563f27d16933 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -68,6 +68,10 @@ impl Map { pub(in crate::iter) fn new(iter: I, f: F) -> Map { Map { iter, f } } + + pub(crate) fn into_inner(self) -> I { + self.iter + } } #[stable(feature = "core_impl_debug", since = "1.9.0")] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index f3311f76a7f06..324bf5c05af20 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -5,6 +5,7 @@ use crate::fmt::{self, Write}; use crate::iter; use crate::mem; use crate::ops; +use core::ascii::EscapeDefault; #[cfg(not(test))] impl [u8] { @@ -250,7 +251,45 @@ impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.clone().try_for_each(|b| f.write_char(b as char)) + // disassemble iterator, including front/back parts of flatmap in case it has been partially consumed + let (front, slice, back) = self.clone().inner.into_parts(); + let front = front.unwrap_or(EscapeDefault::empty()); + let mut bytes = slice.unwrap_or_default().as_slice(); + let back = back.unwrap_or(EscapeDefault::empty()); + + // usually empty, so the formatter won't have to do any work + for byte in front { + f.write_char(byte as char)?; + } + + fn needs_escape(b: u8) -> bool { + b > 0x7E || b < 0x20 || b == b'\\' || b == b'\'' || b == b'"' + } + + while bytes.len() > 0 { + // fast path for the printable, non-escaped subset of ascii + let prefix = bytes.iter().take_while(|&&b| !needs_escape(b)).count(); + // SAFETY: prefix length was derived by counting bytes in the same splice, so it's in-bounds + let (prefix, remainder) = unsafe { bytes.split_at_unchecked(prefix) }; + // SAFETY: prefix is a valid utf8 sequence, as it's a subset of ASCII + let prefix = unsafe { crate::str::from_utf8_unchecked(prefix) }; + + f.write_str(prefix)?; // the fast part + + bytes = remainder; + + if let Some(&b) = bytes.first() { + // guaranteed to be non-empty, better to write it as a str + f.write_str(ascii::escape_default(b).as_str())?; + bytes = &bytes[1..]; + } + } + + // also usually empty + for byte in back { + f.write_char(byte as char)?; + } + Ok(()) } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index f5f2dd0477885..3d3f8ac10c603 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -479,3 +479,13 @@ fn ascii_ctype_const() { is_ascii_control => [false, false, false, false, false]; } } + +#[test] +fn test_ascii_display() { + assert_eq!(b"foo'bar".escape_ascii().to_string(), r#"foo\'bar"#); + assert_eq!(b"\0\xff".escape_ascii().to_string(), r#"\x00\xff"#); + let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); + let _ = it.advance_by(4); + let _ = it.advance_back_by(4); + assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); +} From 130b7e713e879c4c989186d94643be8c834de355 Mon Sep 17 00:00:00 2001 From: Gavin Gray Date: Tue, 21 Nov 2023 20:37:36 +0100 Subject: [PATCH 02/17] Add trait obligation tracking to FulfillCtxt and expose FnCtxt in rustc_infer using callback. Pass each obligation to an fn callback with its respective inference context. This avoids needing to keep around copies of obligations or inference contexts. Specify usability of inspect_typeck in comment. --- compiler/rustc_hir_typeck/src/lib.rs | 24 +++- compiler/rustc_infer/src/infer/at.rs | 1 + compiler/rustc_infer/src/infer/mod.rs | 16 ++- compiler/rustc_infer/src/traits/mod.rs | 8 ++ .../src/solve/fulfill.rs | 136 ++++++++++-------- 5 files changed, 121 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 67c35d717a1ec..80467ca9381e3 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -60,6 +60,7 @@ use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::check_abi; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::ObligationInspector; use rustc_middle::query::Providers; use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -139,7 +140,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); - typeck_with_fallback(tcx, def_id, fallback) + typeck_with_fallback(tcx, def_id, fallback, None) } /// Used only to get `TypeckResults` for type inference during error recovery. @@ -149,14 +150,28 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") }; - typeck_with_fallback(tcx, def_id, fallback) + typeck_with_fallback(tcx, def_id, fallback, None) } -#[instrument(level = "debug", skip(tcx, fallback), ret)] +/// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation. +/// Inspecting obligations only works with the new trait solver. +/// This function is *only to be used* by external tools, it should not be +/// called from within rustc. Note, this is not a query, and thus is not cached. +pub fn inspect_typeck<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + inspect: ObligationInspector<'tcx>, +) -> &'tcx ty::TypeckResults<'tcx> { + let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); + typeck_with_fallback(tcx, def_id, fallback, Some(inspect)) +} + +#[instrument(level = "debug", skip(tcx, fallback, inspector), ret)] fn typeck_with_fallback<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, fallback: impl Fn() -> Ty<'tcx> + 'tcx, + inspector: Option>, ) -> &'tcx ty::TypeckResults<'tcx> { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". @@ -178,6 +193,9 @@ fn typeck_with_fallback<'tcx>( let param_env = tcx.param_env(def_id); let inh = Inherited::new(tcx, def_id); + if let Some(inspector) = inspector { + inh.infcx.attach_obligation_inspector(inspector); + } let mut fcx = FnCtxt::new(&inh, param_env, def_id); if let Some(hir::FnSig { header, decl, .. }) = fn_sig { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index e60e3ffeaa72c..0f1af81d9f04c 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -90,6 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e164041c5991e..39c41a93c3bd1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -13,7 +13,9 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use self::opaque_types::OpaqueTypeStorage; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; -use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt}; +use crate::traits::{ + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt, +}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -334,6 +336,8 @@ pub struct InferCtxt<'tcx> { pub intercrate: bool, next_trait_solver: bool, + + pub obligation_inspector: Cell>>, } impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { @@ -708,6 +712,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, + obligation_inspector: Cell::new(None), } } } @@ -1724,6 +1729,15 @@ impl<'tcx> InferCtxt<'tcx> { } } } + + /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver. + pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) { + debug_assert!( + self.obligation_inspector.get().is_none(), + "shouldn't override a set obligation inspector" + ); + self.obligation_inspector.set(Some(inspector)); + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index fdae093aac8b4..72ec07375ac0e 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -13,12 +13,15 @@ use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; pub use self::ImplSource::*; pub use self::SelectionError::*; +use crate::infer::InferCtxt; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; @@ -116,6 +119,11 @@ pub type PredicateObligations<'tcx> = Vec>; pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; +/// A callback that can be provided to `inspect_typeck`. Invoked on evaluation +/// of root obligations. +pub type ObligationInspector<'tcx> = + fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result); + pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c847425ebf46a..f08622816ec28 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -11,7 +11,7 @@ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use super::eval_ctxt::GenerateProofTree; -use super::{Certainty, InferCtxtEvalExt}; +use super::{Certainty, Goal, InferCtxtEvalExt}; /// A trait engine using the new trait solver. /// @@ -43,6 +43,21 @@ impl<'tcx> FulfillmentCtxt<'tcx> { ); FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() } } + + fn inspect_evaluated_obligation( + &self, + infcx: &InferCtxt<'tcx>, + obligation: &PredicateObligation<'tcx>, + result: &Result<(bool, Certainty, Vec>>), NoSolution>, + ) { + if let Some(inspector) = infcx.obligation_inspector.get() { + let result = match result { + Ok((_, c, _)) => Ok(*c), + Err(NoSolution) => Err(NoSolution), + }; + (inspector)(infcx, &obligation, result); + } + } } impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { @@ -100,65 +115,66 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty, nested_goals) = - match infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0 { - Ok(result) => result, - Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { - FulfillmentErrorCode::ProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::NormalizesTo(..) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::SelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); - continue; - } - }; + let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0; + self.inspect_evaluated_obligation(infcx, &obligation, &result); + let (changed, certainty, nested_goals) = match result { + Ok(result) => result, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + FulfillmentErrorCode::ProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::NormalizesTo(..) => { + FulfillmentErrorCode::ProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::ProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::SubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::SubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::SelectionError( + SelectionError::Unimplemented, + ) + } + ty::PredicateKind::ConstEquate(..) => { + bug!("unexpected goal: {goal:?}") + } + }, + root_obligation: obligation, + }); + continue; + } + }; // Push any nested goals that we get from unifying our canonical response // with our obligation onto the fulfillment context. self.obligations.extend(nested_goals.into_iter().map(|goal| { From 50b4ca637d5d24e47df5cd453d136185d5ece7df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 18 Jan 2024 16:43:49 +0000 Subject: [PATCH 03/17] Teach tidy about line/col information for malformed features --- src/tools/tidy/src/features.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 8e791a7dc69cb..d673ce7a736d9 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -15,7 +15,7 @@ use std::ffi::OsStr; use std::fmt; use std::fs; use std::num::NonZeroU32; -use std::path::Path; +use std::path::{Path, PathBuf}; use regex::Regex; @@ -52,6 +52,8 @@ pub struct Feature { pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, + pub file: PathBuf, + pub line: usize, } impl Feature { fn tracking_issue_display(&self) -> impl fmt::Display { @@ -184,23 +186,25 @@ pub fn check( .chain(lib_features.iter().map(|feat| (feat, "lib"))); for ((feature_name, feature), kind) in all_features_iter { let since = if let Some(since) = feature.since { since } else { continue }; + let file = feature.file.display(); + let line = feature.line; if since > version && since != Version::CurrentPlaceholder { tidy_error!( bad, - "The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}" + "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}" ); } if channel == "nightly" && since == version { tidy_error!( bad, - "The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}", + "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}", version::VERSION_PLACEHOLDER ); } if channel != "nightly" && since == Version::CurrentPlaceholder { tidy_error!( bad, - "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel", + "{file}:{line}: The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel", ); } } @@ -433,7 +437,14 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba ); } Entry::Vacant(e) => { - e.insert(Feature { level, since, has_gate_test: false, tracking_issue }); + e.insert(Feature { + level, + since, + has_gate_test: false, + tracking_issue, + file: path.to_path_buf(), + line: line_number, + }); } } } @@ -559,6 +570,8 @@ fn map_lib_features( since: None, has_gate_test: false, tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none), + file: file.to_path_buf(), + line: i + 1, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -588,7 +601,14 @@ fn map_lib_features( }; let tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none); - let feature = Feature { level, since, has_gate_test: false, tracking_issue }; + let feature = Feature { + level, + since, + has_gate_test: false, + tracking_issue, + file: file.to_path_buf(), + line: i + 1, + }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); } else { From 225f0b9fef38bd7b841bff9911e0ced586dce812 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 19 Jan 2024 16:37:50 +0000 Subject: [PATCH 04/17] Make the remaining "private" fields actually private --- compiler/stable_mir/src/ty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index eba2ac57012b9..b0a08cd9b792c 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -12,7 +12,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Ty(pub usize); +pub struct Ty(usize); impl Debug for Ty { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -138,7 +138,7 @@ impl Const { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ConstId(pub usize); +pub struct ConstId(usize); type Ident = Opaque; From 615946db4fc812bff3bb015dfe860c10da4b20c1 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 5 Dec 2023 22:15:26 +0000 Subject: [PATCH 05/17] Stabilize simple offset_of --- .../src/error_codes/E0795.md | 4 +- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_typeck/src/expr.rs | 12 ++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/lib.rs | 2 +- library/core/src/mem/mod.rs | 14 ++--- library/core/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - .../feature-gate-offset-of-enum.rs | 2 +- .../feature-gate-offset-of-nested.rs | 28 ++++++++++ .../feature-gate-offset-of-nested.stderr | 55 +++++++++++++++++++ .../dead-code/offset-of-correct-param-env.rs | 2 +- tests/ui/lint/dead-code/offset-of.rs | 2 +- tests/ui/offset-of/offset-of-arg-count.rs | 2 - tests/ui/offset-of/offset-of-arg-count.stderr | 14 ++--- tests/ui/offset-of/offset-of-dst-field.rs | 2 +- tests/ui/offset-of/offset-of-enum.rs | 2 +- tests/ui/offset-of/offset-of-inference.rs | 2 - tests/ui/offset-of/offset-of-inference.stderr | 2 +- tests/ui/offset-of/offset-of-must-use.rs | 1 - tests/ui/offset-of/offset-of-must-use.stderr | 4 +- tests/ui/offset-of/offset-of-output-type.rs | 2 - .../ui/offset-of/offset-of-output-type.stderr | 12 ++-- tests/ui/offset-of/offset-of-private.rs | 2 +- tests/ui/offset-of/offset-of-self.rs | 2 +- tests/ui/offset-of/offset-of-tuple-nested.rs | 2 +- tests/ui/offset-of/offset-of-tuple.rs | 2 +- tests/ui/offset-of/offset-of-unsized.rs | 2 - .../offset-of-unstable-with-feature.rs | 2 +- tests/ui/offset-of/offset-of-unstable.rs | 2 +- 30 files changed, 134 insertions(+), 49 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-offset-of-nested.rs create mode 100644 tests/ui/feature-gates/feature-gate-offset-of-nested.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md index 20f51441c2911..ad77d72c913a8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0795.md +++ b/compiler/rustc_error_codes/src/error_codes/E0795.md @@ -3,7 +3,7 @@ Invalid argument for the `offset_of!` macro. Erroneous code example: ```compile_fail,E0795 -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] let x = std::mem::offset_of!(Option, Some); ``` @@ -16,7 +16,7 @@ The offset of the contained `u8` in the `Option` can be found by specifying the field name `0`: ``` -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] let x: usize = std::mem::offset_of!(Option, Some.0); ``` diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2f2b551e6ecf7..c512ccc90db5c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -550,6 +550,8 @@ declare_features! ( (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(106655)), + /// Allows using multiple nested field accesses in offset_of! + (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(106655)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows macro attributes on expressions, statements and non-inline modules. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4b1ad28f0941d..242e8dc95e23c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3246,6 +3246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let container = self.to_ty(container).normalized; + if let Some(ident_2) = fields.get(1) + && !self.tcx.features().offset_of_nested + { + rustc_session::parse::feature_err( + &self.tcx.sess.parse_sess, + sym::offset_of_nested, + ident_2.span, + "only a single ident or integer is stable as the field in offset_of", + ) + .emit(); + } + let mut field_indices = Vec::with_capacity(fields.len()); let mut current_container = container; let mut fields = fields.into_iter(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 44795022cbab3..7b0138d50baed 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1153,6 +1153,7 @@ symbols! { offset, offset_of, offset_of_enum, + offset_of_nested, ok_or_else, omit_gdb_pretty_printer_section, on, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1a8f245c8be30..81bf6f28693f1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -111,6 +111,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(not(bootstrap), feature(offset_of_nested))] #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] @@ -176,7 +177,6 @@ #![feature(isqrt)] #![feature(maybe_uninit_uninit_array)] #![feature(non_null_convenience)] -#![feature(offset_of)] #![feature(offset_of_enum)] #![feature(panic_internals)] #![feature(ptr_alignment_type)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 407954001e4ce..f04ccce40f109 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1303,11 +1303,12 @@ impl SizedTypeProperties for T {} /// Enum variants may be traversed as if they were fields. Variants themselves do /// not have an offset. /// +/// However, on stable only a single field name is supported, which blocks the use of +/// enum support. +/// /// Visibility is respected - all types and fields must be visible to the call site: /// /// ``` -/// #![feature(offset_of)] -/// /// mod nested { /// #[repr(C)] /// pub struct Struct { @@ -1330,8 +1331,6 @@ impl SizedTypeProperties for T {} /// not *identical*, e.g.: /// /// ``` -/// #![feature(offset_of)] -/// /// struct Wrapper(T, U); /// /// type A = Wrapper; @@ -1359,8 +1358,7 @@ impl SizedTypeProperties for T {} /// # Examples /// /// ``` -/// #![feature(offset_of)] -/// # #![feature(offset_of_enum)] +/// #![feature(offset_of_enum, offset_of_nested)] /// /// use std::mem; /// #[repr(C)] @@ -1396,7 +1394,7 @@ impl SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` #[cfg(not(bootstrap))] -#[unstable(feature = "offset_of", issue = "106655")] +#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { // The `{}` is for better error messages @@ -1404,7 +1402,7 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { } #[cfg(bootstrap)] -#[unstable(feature = "offset_of", issue = "106655")] +#[stable(feature = "offset_of", since = "CURRENT_RUSTC_VERSION")] #[allow_internal_unstable(builtin_syntax, hint_must_use)] #[allow(missing_docs)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8604d41eb6860..02af3e6f9476a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -115,7 +115,6 @@ #![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] -#![feature(offset_of)] #![feature(iter_map_windows)] #![allow(internal_features)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7a8d9d0ceeca6..4b33ad5dfe092 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -329,7 +329,6 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] -#![feature(offset_of)] #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs index e19dcf9f6a54c..1f2f7ee1e1919 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-enum.rs +++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.rs b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs new file mode 100644 index 0000000000000..c4eb4720fde5e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.rs @@ -0,0 +1,28 @@ +#![feature(offset_of_enum)] + +use std::mem::offset_of; + +struct S { + a: u8, + b: (u8, u8), + c: T, +} + +struct T { + t: &'static str, +} + +enum Alpha { + One(u8), + Two(u8), +} + +fn main() { + offset_of!(Alpha, Two.0); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, a); + offset_of!((u8, S), 1); + offset_of!((u32, (S, T)), 1.1); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, b.0); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!((S, ()), 0.c); //~ ERROR only a single ident or integer is stable as the field in offset_of + offset_of!(S, c.t); //~ ERROR only a single ident or integer is stable as the field in offset_of +} diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr new file mode 100644 index 0000000000000..ebc251fd66307 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr @@ -0,0 +1,55 @@ +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:21:27 + | +LL | offset_of!(Alpha, Two.0); + | ^ + | + = note: see issue #106655 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:24:33 + | +LL | offset_of!((u32, (S, T)), 1.1); + | _____----------------------------^- + | | | + | | in this macro invocation +LL | | offset_of!(S, b.0); +LL | | offset_of!((S, ()), 0.c); +LL | | offset_of!(S, c.t); +... | + | + = note: see issue #106655 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:25:21 + | +LL | offset_of!(S, b.0); + | ^ + | + = note: see issue #106655 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:26:27 + | +LL | offset_of!((S, ()), 0.c); + | ^ + | + = note: see issue #106655 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + +error[E0658]: only a single ident or integer is stable as the field in offset_of + --> $DIR/feature-gate-offset-of-nested.rs:27:21 + | +LL | offset_of!(S, c.t); + | ^ + | + = note: see issue #106655 for more information + = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs index 2c6fcef250049..ae81a2524396c 100644 --- a/tests/ui/lint/dead-code/offset-of-correct-param-env.rs +++ b/tests/ui/lint/dead-code/offset-of-correct-param-env.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(offset_of)] +#![feature(offset_of_nested)] #![deny(dead_code)] // This struct contains a projection that can only be normalized after getting the field type. diff --git a/tests/ui/lint/dead-code/offset-of.rs b/tests/ui/lint/dead-code/offset-of.rs index da91de3862fc8..5269426d2ff3a 100644 --- a/tests/ui/lint/dead-code/offset-of.rs +++ b/tests/ui/lint/dead-code/offset-of.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] #![deny(dead_code)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 7b92698c25e8a..c86e61a61a725 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -1,5 +1,3 @@ -#![feature(offset_of)] - use std::mem::offset_of; fn main() { diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index af0d42de30d60..4cb24b3d034b6 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -1,5 +1,5 @@ error: unexpected end of macro invocation - --> $DIR/offset-of-arg-count.rs:6:34 + --> $DIR/offset-of-arg-count.rs:4:34 | LL | offset_of!(NotEnoughArguments); | ^ missing tokens in macro arguments @@ -8,7 +8,7 @@ note: while trying to match `,` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: unexpected end of macro invocation - --> $DIR/offset-of-arg-count.rs:7:45 + --> $DIR/offset-of-arg-count.rs:5:45 | LL | offset_of!(NotEnoughArgumentsWithAComma, ); | ^ missing tokens in macro arguments @@ -17,7 +17,7 @@ note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: no rules expected the token `too` - --> $DIR/offset-of-arg-count.rs:8:34 + --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(Container, field, too many arguments); | ^^^ no rules expected this token in macro call @@ -25,25 +25,25 @@ LL | offset_of!(Container, field, too many arguments); = note: while trying to match sequence end error: unexpected token: `)` - --> $DIR/offset-of-arg-count.rs:11:21 + --> $DIR/offset-of-arg-count.rs:9:21 | LL | offset_of!(S, f.); | ^ error: unexpected token: `,` - --> $DIR/offset-of-arg-count.rs:12:21 + --> $DIR/offset-of-arg-count.rs:10:21 | LL | offset_of!(S, f.,); | ^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-arg-count.rs:13:19 + --> $DIR/offset-of-arg-count.rs:11:19 | LL | offset_of!(S, f..); | ^^^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-arg-count.rs:14:19 + --> $DIR/offset-of-arg-count.rs:12:19 | LL | offset_of!(S, f..,); | ^^^ diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index e393b159e64d5..016ebfadd1420 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, extern_types)] +#![feature(extern_types)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index a2d6aace47da1..cb2f04786ac5c 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-inference.rs b/tests/ui/offset-of/offset-of-inference.rs index ba87574eae047..1b1ae25e1ee65 100644 --- a/tests/ui/offset-of/offset-of-inference.rs +++ b/tests/ui/offset-of/offset-of-inference.rs @@ -1,7 +1,5 @@ // Test that inference types in `offset_of!` don't ICE. -#![feature(offset_of)] - struct Foo { x: T, } diff --git a/tests/ui/offset-of/offset-of-inference.stderr b/tests/ui/offset-of/offset-of-inference.stderr index 1845822f11db1..8bd104ed7e277 100644 --- a/tests/ui/offset-of/offset-of-inference.stderr +++ b/tests/ui/offset-of/offset-of-inference.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/offset-of-inference.rs:10:35 + --> $DIR/offset-of-inference.rs:8:35 | LL | let _ = core::mem::offset_of!(Foo<_>, x); | ^^^^^^ cannot infer type diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs index e30145d7a2fe3..e4b092fcedf3b 100644 --- a/tests/ui/offset-of/offset-of-must-use.rs +++ b/tests/ui/offset-of/offset-of-must-use.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(offset_of)] #![warn(unused)] fn main() { diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr index 5fe387a72553c..b6d88e098d00c 100644 --- a/tests/ui/offset-of/offset-of-must-use.stderr +++ b/tests/ui/offset-of/offset-of-must-use.stderr @@ -1,11 +1,11 @@ warning: unused return value of `must_use` that must be used - --> $DIR/offset-of-must-use.rs:7:5 + --> $DIR/offset-of-must-use.rs:6:5 | LL | core::mem::offset_of!((String,), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/offset-of-must-use.rs:4:9 + --> $DIR/offset-of-must-use.rs:3:9 | LL | #![warn(unused)] | ^^^^^^ diff --git a/tests/ui/offset-of/offset-of-output-type.rs b/tests/ui/offset-of/offset-of-output-type.rs index 50c2e93841f9f..76a33154ba3d1 100644 --- a/tests/ui/offset-of/offset-of-output-type.rs +++ b/tests/ui/offset-of/offset-of-output-type.rs @@ -1,5 +1,3 @@ -#![feature(offset_of)] - use std::mem::offset_of; struct S { diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr index 233d49876436a..34ad931d0caac 100644 --- a/tests/ui/offset-of/offset-of-output-type.stderr +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:12:17 + --> $DIR/offset-of-output-type.rs:10:17 | LL | let _: u8 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` @@ -7,7 +7,7 @@ LL | let _: u8 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:13:18 + --> $DIR/offset-of-output-type.rs:11:18 | LL | let _: u16 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` @@ -15,7 +15,7 @@ LL | let _: u16 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:14:18 + --> $DIR/offset-of-output-type.rs:12:18 | LL | let _: u32 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` @@ -23,7 +23,7 @@ LL | let _: u32 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:15:18 + --> $DIR/offset-of-output-type.rs:13:18 | LL | let _: u64 = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` @@ -31,7 +31,7 @@ LL | let _: u64 = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:16:20 + --> $DIR/offset-of-output-type.rs:14:20 | LL | let _: isize = offset_of!(S, v); | ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` @@ -39,7 +39,7 @@ LL | let _: isize = offset_of!(S, v); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/offset-of-output-type.rs:19:5 + --> $DIR/offset-of-output-type.rs:17:5 | LL | fn main() { | - expected `()` because of default return type diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs index b7affdb794395..1c326b5c79a5e 100644 --- a/tests/ui/offset-of/offset-of-private.rs +++ b/tests/ui/offset-of/offset-of-private.rs @@ -1,4 +1,4 @@ -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs index 04dcaf7c0a6b6..1558e13b53095 100644 --- a/tests/ui/offset-of/offset-of-self.rs +++ b/tests/ui/offset-of/offset-of-self.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-tuple-nested.rs b/tests/ui/offset-of/offset-of-tuple-nested.rs index 59b02e3c5c433..212176b24271a 100644 --- a/tests/ui/offset-of/offset-of-tuple-nested.rs +++ b/tests/ui/offset-of/offset-of-tuple-nested.rs @@ -2,7 +2,7 @@ // Test for issue #112204 -- make sure this goes through the entire compilation pipeline, // similar to why `offset-of-unsized.rs` is also build-pass -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index b6fc1e32229a1..75ba8d77f2fbd 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -1,4 +1,4 @@ -#![feature(offset_of)] +#![feature(offset_of_nested)] #![feature(builtin_syntax)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs index 49c8328da5c55..b70529ed7b85e 100644 --- a/tests/ui/offset-of/offset-of-unsized.rs +++ b/tests/ui/offset-of/offset-of-unsized.rs @@ -2,8 +2,6 @@ // regression test for #112051, not in `offset-of-dst` as the issue is in codegen, // and isn't triggered in the presence of typeck errors -#![feature(offset_of)] - struct S { a: u64, b: T, diff --git a/tests/ui/offset-of/offset-of-unstable-with-feature.rs b/tests/ui/offset-of/offset-of-unstable-with-feature.rs index 7d2eb46c056eb..be275564a0a4f 100644 --- a/tests/ui/offset-of/offset-of-unstable-with-feature.rs +++ b/tests/ui/offset-of/offset-of-unstable-with-feature.rs @@ -1,7 +1,7 @@ // check-pass // aux-build:offset-of-staged-api.rs -#![feature(offset_of, unstable_test_feature)] +#![feature(offset_of_nested, unstable_test_feature)] use std::mem::offset_of; diff --git a/tests/ui/offset-of/offset-of-unstable.rs b/tests/ui/offset-of/offset-of-unstable.rs index 1e19f2091f29f..da0882abd2286 100644 --- a/tests/ui/offset-of/offset-of-unstable.rs +++ b/tests/ui/offset-of/offset-of-unstable.rs @@ -1,6 +1,6 @@ // aux-build:offset-of-staged-api.rs -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::mem::offset_of; From 803b810eac520c11c7f1ea0a81af535ee9bddd61 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Fri, 5 Jan 2024 21:25:01 +0000 Subject: [PATCH 06/17] Remove feature(offset_of) from tests --- library/core/tests/lib.rs | 1 + tests/mir-opt/const_prop/offset_of.rs | 2 +- tests/mir-opt/dataflow-const-prop/offset_of.rs | 2 +- tests/pretty/offset_of.rs | 1 - tests/ui/layout/issue-112048-unsizing-niche.rs | 1 - 5 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 02af3e6f9476a..13fb97fdc7f3e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -59,6 +59,7 @@ #![feature(noop_waker)] #![feature(numfmt)] #![feature(num_midpoint)] +#![cfg_attr(not(bootstrap), feature(offset_of_nested))] #![feature(isqrt)] #![feature(step_trait)] #![feature(str_internals)] diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 43ecbbed186f6..f15d15bfcb268 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -2,7 +2,7 @@ // unit-test: GVN // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(offset_of, offset_of_enum)] +#![feature(offset_of_enum, offset_of_nested)] use std::marker::PhantomData; use std::mem::offset_of; diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs index e71b3f59ecab3..c1be691025805 100644 --- a/tests/mir-opt/dataflow-const-prop/offset_of.rs +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -2,7 +2,7 @@ // unit-test: DataflowConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(offset_of)] +#![feature(offset_of_nested)] use std::marker::PhantomData; use std::mem::offset_of; diff --git a/tests/pretty/offset_of.rs b/tests/pretty/offset_of.rs index e1783432857e2..1307c335ad322 100644 --- a/tests/pretty/offset_of.rs +++ b/tests/pretty/offset_of.rs @@ -1,4 +1,3 @@ // pp-exact -#![feature(offset_of)] fn main() { std::mem::offset_of!(std :: ops :: Range < usize >, end); } diff --git a/tests/ui/layout/issue-112048-unsizing-niche.rs b/tests/ui/layout/issue-112048-unsizing-niche.rs index 23588ba36ee59..e59e063df99be 100644 --- a/tests/ui/layout/issue-112048-unsizing-niche.rs +++ b/tests/ui/layout/issue-112048-unsizing-niche.rs @@ -2,7 +2,6 @@ // Check that unsizing does not change which field is considered for niche layout. -#![feature(offset_of)] #![allow(dead_code)] #[derive(Clone)] From 7924c9bcdfa0ec5980474ac680439d7fc2a4690f Mon Sep 17 00:00:00 2001 From: George Bateman Date: Fri, 19 Jan 2024 20:29:40 +0000 Subject: [PATCH 07/17] Split remaining offset_of features into new tracking issues --- compiler/rustc_feature/src/unstable.rs | 4 ++-- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../feature-gate-offset-of-enum.stderr | 4 ++-- .../feature-gate-offset-of-nested.stderr | 15 ++++++++++----- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c512ccc90db5c..371b651f5e857 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -549,9 +549,9 @@ declare_features! ( /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! - (unstable, offset_of_enum, "1.75.0", Some(106655)), + (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using multiple nested field accesses in offset_of! - (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(106655)), + (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows macro attributes on expressions, statements and non-inline modules. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 242e8dc95e23c..33d7ba6268a20 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3250,7 +3250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !self.tcx.features().offset_of_nested { rustc_session::parse::feature_err( - &self.tcx.sess.parse_sess, + &self.tcx.sess, sym::offset_of_nested, ident_2.span, "only a single ident or integer is stable as the field in offset_of", diff --git a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr index 02ee54e8607ac..fc7dd7923f7a8 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr +++ b/tests/ui/feature-gates/feature-gate-offset-of-enum.stderr @@ -13,7 +13,7 @@ error[E0658]: using enums in offset_of is experimental LL | offset_of!(Alpha, One); | ^^^ | - = note: see issue #106655 for more information + = note: see issue #120141 for more information = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -29,7 +29,7 @@ error[E0658]: using enums in offset_of is experimental LL | offset_of!(Alpha, Two.0); | ^^^ | - = note: see issue #106655 for more information + = note: see issue #120141 for more information = help: add `#![feature(offset_of_enum)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr index ebc251fd66307..f367fc9fa0dd4 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr +++ b/tests/ui/feature-gates/feature-gate-offset-of-nested.stderr @@ -4,8 +4,9 @@ error[E0658]: only a single ident or integer is stable as the field in offset_of LL | offset_of!(Alpha, Two.0); | ^ | - = note: see issue #106655 for more information + = note: see issue #120140 for more information = help: add `#![feature(offset_of_nested)]` 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]: only a single ident or integer is stable as the field in offset_of --> $DIR/feature-gate-offset-of-nested.rs:24:33 @@ -19,8 +20,9 @@ LL | | offset_of!((S, ()), 0.c); LL | | offset_of!(S, c.t); ... | | - = note: see issue #106655 for more information + = note: see issue #120140 for more information = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: only a single ident or integer is stable as the field in offset_of @@ -29,8 +31,9 @@ error[E0658]: only a single ident or integer is stable as the field in offset_of LL | offset_of!(S, b.0); | ^ | - = note: see issue #106655 for more information + = note: see issue #120140 for more information = help: add `#![feature(offset_of_nested)]` 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]: only a single ident or integer is stable as the field in offset_of --> $DIR/feature-gate-offset-of-nested.rs:26:27 @@ -38,8 +41,9 @@ error[E0658]: only a single ident or integer is stable as the field in offset_of LL | offset_of!((S, ()), 0.c); | ^ | - = note: see issue #106655 for more information + = note: see issue #120140 for more information = help: add `#![feature(offset_of_nested)]` 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]: only a single ident or integer is stable as the field in offset_of --> $DIR/feature-gate-offset-of-nested.rs:27:21 @@ -47,8 +51,9 @@ error[E0658]: only a single ident or integer is stable as the field in offset_of LL | offset_of!(S, c.t); | ^ | - = note: see issue #106655 for more information + = note: see issue #120140 for more information = help: add `#![feature(offset_of_nested)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 5 previous errors From 0943a6b188e11339d217d43f39322f51d2d8187d Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Sat, 20 Jan 2024 01:22:52 +0400 Subject: [PATCH 08/17] add test issue-117965 --- tests/ui/single-use-lifetime/issue-117965.rs | 18 ++++++++++++++++ .../single-use-lifetime/issue-117965.stderr | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ui/single-use-lifetime/issue-117965.rs create mode 100644 tests/ui/single-use-lifetime/issue-117965.stderr diff --git a/tests/ui/single-use-lifetime/issue-117965.rs b/tests/ui/single-use-lifetime/issue-117965.rs new file mode 100644 index 0000000000000..5eb2a03e13da4 --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-117965.rs @@ -0,0 +1,18 @@ +#![deny(single_use_lifetimes)] + +pub enum Data<'a> { + Borrowed(&'a str), + Owned(String), +} + +impl<'a> Data<'a> { + pub fn get<'b: 'a>(&'b self) -> &'a str { + //~^ ERROR lifetime parameter `'b` only used once + match &self { + Self::Borrowed(val) => val, + Self::Owned(val) => &val, + } + } +} + +fn main() {} diff --git a/tests/ui/single-use-lifetime/issue-117965.stderr b/tests/ui/single-use-lifetime/issue-117965.stderr new file mode 100644 index 0000000000000..e789e1835462f --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-117965.stderr @@ -0,0 +1,21 @@ +error: lifetime parameter `'b` only used once + --> $DIR/issue-117965.rs:9:16 + | +LL | pub fn get<'b: 'a>(&'b self) -> &'a str { + | ^^ -- ...is used only here + | | + | this lifetime... + | +note: the lint level is defined here + --> $DIR/issue-117965.rs:1:9 + | +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ +help: elide the single-use lifetime + | +LL - pub fn get<'b: 'a>(&'b self) -> &'a str { +LL + pub fn get(&self) -> &'a str { + | + +error: aborting due to 1 previous error + From 4459be7bd59c781c850ab48679ef3a1e420e9f99 Mon Sep 17 00:00:00 2001 From: SOFe Date: Sat, 29 Oct 2022 22:15:04 +0800 Subject: [PATCH 09/17] Added NonZeroXxx::from_mut(_unchecked)? --- library/core/src/num/nonzero.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7d60686597a0d..582c6796781a2 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -171,6 +171,32 @@ macro_rules! nonzero_integer { } } + /// Converts a primitive mutable reference to a non-zero mutable reference + /// if the referenced integer is not zero. + #[unstable(feature = "nonzero_from_mut", issue = "none")] + #[must_use] + #[inline] + pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { + // SAFETY: Self is repr(transparent), and the value is non-zero. + // As long as the returned reference is alive, + // the user cannot `*n = 0` directly. + (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) }) + } + + /// Converts a primitive mutable reference to a non-zero mutable reference + /// without checking whether the referenced value is non-zero. + /// This results in undefined behavior if `*n` is zero. + /// + /// # Safety + /// The referenced value must not be currently zero. + #[unstable(feature = "nonzero_from_mut", issue = "none")] + #[must_use] + #[inline] + pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self { + // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero. + unsafe { &mut *(n as *mut $Int as *mut Self) } + } + /// Returns the value as a primitive type. #[$stability] #[inline] From 3acb445f15d69c982c37df15a27d06b43ca6e388 Mon Sep 17 00:00:00 2001 From: SOFe Date: Sun, 30 Oct 2022 14:49:24 +0800 Subject: [PATCH 10/17] Added assert_unsafe_precondition! check for NonZeroXxx::from_mut_unchecked --- library/core/src/num/nonzero.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 582c6796781a2..53ee6efcba7cb 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -171,18 +171,6 @@ macro_rules! nonzero_integer { } } - /// Converts a primitive mutable reference to a non-zero mutable reference - /// if the referenced integer is not zero. - #[unstable(feature = "nonzero_from_mut", issue = "none")] - #[must_use] - #[inline] - pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { - // SAFETY: Self is repr(transparent), and the value is non-zero. - // As long as the returned reference is alive, - // the user cannot `*n = 0` directly. - (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) }) - } - /// Converts a primitive mutable reference to a non-zero mutable reference /// without checking whether the referenced value is non-zero. /// This results in undefined behavior if `*n` is zero. @@ -194,7 +182,26 @@ macro_rules! nonzero_integer { #[inline] pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self { // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero. - unsafe { &mut *(n as *mut $Int as *mut Self) } + unsafe { + let n_alias = &mut *n; + core::intrinsics::assert_unsafe_precondition!( + concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"), + (n_alias: &mut $Int) => *n_alias != 0 + ); + &mut *(n as *mut $Int as *mut Self) + } + } + + /// Converts a primitive mutable reference to a non-zero mutable reference + /// if the referenced integer is not zero. + #[unstable(feature = "nonzero_from_mut", issue = "none")] + #[must_use] + #[inline] + pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { + // SAFETY: Self is repr(transparent), and the value is non-zero. + // As long as the returned reference is alive, + // the user cannot `*n = 0` directly. + (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) }) } /// Returns the value as a primitive type. From 596410eb36c90c501fc57f68d81a57b6e0053a5c Mon Sep 17 00:00:00 2001 From: SOFe Date: Fri, 30 Dec 2022 22:50:41 +0800 Subject: [PATCH 11/17] Assign tracking issue number for feature(nonzero_from_mut) --- library/core/src/num/nonzero.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 53ee6efcba7cb..bda691b16d4a7 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -177,7 +177,7 @@ macro_rules! nonzero_integer { /// /// # Safety /// The referenced value must not be currently zero. - #[unstable(feature = "nonzero_from_mut", issue = "none")] + #[unstable(feature = "nonzero_from_mut", issue = "106290")] #[must_use] #[inline] pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self { @@ -194,7 +194,7 @@ macro_rules! nonzero_integer { /// Converts a primitive mutable reference to a non-zero mutable reference /// if the referenced integer is not zero. - #[unstable(feature = "nonzero_from_mut", issue = "none")] + #[unstable(feature = "nonzero_from_mut", issue = "106290")] #[must_use] #[inline] pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { From de2575f35d46dfa2b24eb205ef133a679bff1b31 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Sat, 20 Jan 2024 02:30:58 +0400 Subject: [PATCH 12/17] Don't delete any lifetimes with bounds --- compiler/rustc_resolve/src/late/diagnostics.rs | 3 ++- tests/ui/single-use-lifetime/issue-117965.stderr | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 5a95f2083f666..abb0a7a465aa1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2567,8 +2567,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { debug!(?param.ident, ?param.ident.span, ?use_span); let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let deletion_span = + if param.bounds.is_empty() { deletion_span() } else { None }; - let deletion_span = deletion_span(); self.r.lint_buffer.buffer_lint_with_diagnostic( lint::builtin::SINGLE_USE_LIFETIMES, param.id, diff --git a/tests/ui/single-use-lifetime/issue-117965.stderr b/tests/ui/single-use-lifetime/issue-117965.stderr index e789e1835462f..ed14ab92f4d16 100644 --- a/tests/ui/single-use-lifetime/issue-117965.stderr +++ b/tests/ui/single-use-lifetime/issue-117965.stderr @@ -11,11 +11,6 @@ note: the lint level is defined here | LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ -help: elide the single-use lifetime - | -LL - pub fn get<'b: 'a>(&'b self) -> &'a str { -LL + pub fn get(&self) -> &'a str { - | error: aborting due to 1 previous error From b72af9fe9b01002fd0e352cd7e98ab811a014452 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 19 Jan 2024 18:02:05 -0500 Subject: [PATCH 13/17] Stabilize `round_ties_even` --- library/std/src/f32.rs | 4 +--- library/std/src/f64.rs | 4 +--- library/std/src/lib.rs | 1 - src/tools/miri/src/lib.rs | 1 - src/tools/miri/tests/pass/float.rs | 1 - 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c3506175715fe..1b38ba721147c 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -102,8 +102,6 @@ impl f32 { /// # Examples /// /// ``` - /// #![feature(round_ties_even)] - /// /// let f = 3.3_f32; /// let g = -3.3_f32; /// let h = 3.5_f32; @@ -116,7 +114,7 @@ impl f32 { /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "round_ties_even", issue = "96710")] + #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn round_ties_even(self) -> f32 { unsafe { intrinsics::rintf32(self) } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index e4b7bfeeb84af..f8fc84440ae5c 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -102,8 +102,6 @@ impl f64 { /// # Examples /// /// ``` - /// #![feature(round_ties_even)] - /// /// let f = 3.3_f64; /// let g = -3.3_f64; /// let h = 3.5_f64; @@ -116,7 +114,7 @@ impl f64 { /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "round_ties_even", issue = "96710")] + #[stable(feature = "round_ties_even", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn round_ties_even(self) -> f64 { unsafe { intrinsics::rintf64(self) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7a8d9d0ceeca6..11d655042b716 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -338,7 +338,6 @@ #![feature(prelude_2024)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] -#![feature(round_ties_even)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_range)] diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index cacd02bbfaee1..80a47c852692c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -8,7 +8,6 @@ #![feature(variant_count)] #![feature(yeet_expr)] #![feature(nonzero_ops)] -#![feature(round_ties_even)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(int_roundings)] diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 5f2d4489f4ac1..1bb44d56bf6b5 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,5 +1,4 @@ #![feature(stmt_expr_attributes)] -#![feature(round_ties_even)] #![feature(float_gamma)] #![allow(arithmetic_overflow)] From b1688b48d2841a1421cb7ed0afd32ce0c3eeb20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 8 Jan 2024 23:00:06 +0000 Subject: [PATCH 14/17] Avoid ICE: Check diagnostic is error before downgrading Fix #119633. --- .../rustc_hir_analysis/src/astconv/lint.rs | 8 +-- .../object-safety/avoid-ice-on-warning-2.rs | 9 ++++ .../avoid-ice-on-warning-2.stderr | 50 +++++++++++++++++++ .../ui/object-safety/avoid-ice-on-warning.rs | 6 +++ .../object-safety/avoid-ice-on-warning.stderr | 29 +++++++++++ 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 tests/ui/object-safety/avoid-ice-on-warning-2.rs create mode 100644 tests/ui/object-safety/avoid-ice-on-warning-2.stderr create mode 100644 tests/ui/object-safety/avoid-ice-on-warning.rs create mode 100644 tests/ui/object-safety/avoid-ice-on-warning.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 3761d52951709..bf668f311cc61 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -122,7 +122,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ], Applicability::MachineApplicable, ); - } else { + } else if diag.is_error() { // We'll emit the object safety error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } @@ -148,8 +148,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if !is_object_safe { diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); - // We'll emit the object safety error already, with a structured suggestion. - diag.downgrade_to_delayed_bug(); + if diag.is_error() { + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); + } } else { let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { // There are more than one trait bound, we need surrounding parentheses. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.rs b/tests/ui/object-safety/avoid-ice-on-warning-2.rs new file mode 100644 index 0000000000000..cd34362d3dd52 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.rs @@ -0,0 +1,9 @@ +fn id(f: Copy) -> usize { +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| ERROR the trait `Copy` cannot be made into an object + f() +} +fn main() {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.stderr new file mode 100644 index 0000000000000..2755eee6f3529 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.stderr @@ -0,0 +1,50 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-2.rs:1:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `Copy` it is not object safe, so it can't be `dyn` + = note: `#[warn(bare_trait_objects)]` on by default +help: use a new generic type parameter, constrained by `Copy` + | +LL | fn id(f: T) -> usize { + | +++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn id(f: impl Copy) -> usize { + | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-2.rs:1:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `Copy` it is not object safe, so it can't be `dyn` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use a new generic type parameter, constrained by `Copy` + | +LL | fn id(f: T) -> usize { + | +++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn id(f: impl Copy) -> usize { + | ++++ + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/avoid-ice-on-warning-2.rs:1:13 + | +LL | fn id(f: Copy) -> usize { + | ^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error: aborting due to 1 previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.rs b/tests/ui/object-safety/avoid-ice-on-warning.rs new file mode 100644 index 0000000000000..d2a1eeb5286b0 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning.rs @@ -0,0 +1,6 @@ +fn call_this(f: F) : Fn(&str) + call_that {} +//~^ ERROR return types are denoted using `->` +//~| ERROR cannot find trait `call_that` in this scope +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +fn main() {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning.stderr b/tests/ui/object-safety/avoid-ice-on-warning.stderr new file mode 100644 index 0000000000000..1046f177e8296 --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning.stderr @@ -0,0 +1,29 @@ +error: return types are denoted using `->` + --> $DIR/avoid-ice-on-warning.rs:1:23 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^ help: use `->` instead + +error[E0405]: cannot find trait `call_that` in this scope + --> $DIR/avoid-ice-on-warning.rs:1:36 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^ not found in this scope + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning.rs:1:25 + | +LL | fn call_this(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: `Fn(&str) + call_that` is not object safe, use `impl Fn(&str) + call_that` to return an opaque type, as long as you return a single underlying type + | +LL | fn call_this(f: F) : impl Fn(&str) + call_that {} + | ++++ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0405`. From 6b7e6ea590ad0179e9c61c5e007220ae1e4b9644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Jan 2024 00:22:35 +0000 Subject: [PATCH 15/17] Account for traits using self-trait by name without `dyn` Fix #119652. --- .../rustc_hir_analysis/src/astconv/lint.rs | 24 ++-- ...-trait-should-use-self-2021-without-dyn.rs | 19 ++++ ...it-should-use-self-2021-without-dyn.stderr | 105 ++++++++++++++++++ ...bject-unsafe-trait-should-use-self-2021.rs | 17 +++ ...t-unsafe-trait-should-use-self-2021.stderr | 65 +++++++++++ 5 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs create mode 100644 tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr create mode 100644 tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs create mode 100644 tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index bf668f311cc61..b5f42e98127ee 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -78,14 +78,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; - let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, _), - generics, - .. - })) = tcx.hir_node_by_def_id(parent_id) - else { - return false; + let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { + (sig, generics, None) + } + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + generics, + owner_id, + .. + }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + _ => return false, }; let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return false; @@ -94,6 +97,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|o| match o.trait_ref.path.res { + Res::Def(DefKind::Trait, id) if Some(id) == owner => { + // When we're dealing with a recursive trait, we don't want to downgrade + // the error, so we consider them to be object safe always. (#119652) + true + } Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id), _ => false, }) diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs new file mode 100644 index 0000000000000..6382480b7e335 --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs @@ -0,0 +1,19 @@ +// edition:2021 +#![allow(bare_trait_objects)] +trait A: Sized { + fn f(a: A) -> A; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword +} +trait B { + fn f(a: B) -> B; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword +} +trait C { + fn f(&self, a: C) -> C; + //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR trait objects must include the `dyn` keyword +} + +fn main() {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr new file mode 100644 index 0000000000000..1d8ed54804626 --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr @@ -0,0 +1,105 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | fn f(a: A) -> A; + | ^ + | +help: use a new generic type parameter, constrained by `A` + | +LL | fn f(a: T) -> A; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(a: impl A) -> A; + | ++++ +help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch + | +LL | fn f(a: &dyn A) -> A; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19 + | +LL | fn f(a: A) -> A; + | ^ + | +help: use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: A) -> impl A; + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn f(a: A) -> Box; + | +++++++ + + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:13 + | +LL | fn f(a: B) -> B; + | ^ + | +help: use a new generic type parameter, constrained by `B` + | +LL | fn f(a: T) -> B; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(a: impl B) -> B; + | ++++ +help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch + | +LL | fn f(a: &dyn B) -> B; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:19 + | +LL | fn f(a: B) -> B; + | ^ + | +help: use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: B) -> impl B; + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn f(a: B) -> Box; + | +++++++ + + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:20 + | +LL | fn f(&self, a: C) -> C; + | ^ + | +help: use a new generic type parameter, constrained by `C` + | +LL | fn f(&self, a: T) -> C; + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn f(&self, a: impl C) -> C; + | ++++ +help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch + | +LL | fn f(&self, a: &dyn C) -> C; + | ++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:26 + | +LL | fn f(&self, a: C) -> C; + | ^ + | +help: use `impl C` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(&self, a: C) -> impl C; + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn f(&self, a: C) -> Box; + | +++++++ + + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs new file mode 100644 index 0000000000000..a598e883f3fdd --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs @@ -0,0 +1,17 @@ +// edition:2021 +#![allow(bare_trait_objects)] +trait A: Sized { + fn f(a: dyn A) -> dyn A; + //~^ ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `A` cannot be made into an object +} +trait B { + fn f(a: dyn B) -> dyn B; + //~^ ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `B` cannot be made into an object +} +trait C { + fn f(&self, a: dyn C) -> dyn C; +} + +fn main() {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr new file mode 100644 index 0000000000000..d6376be9c046c --- /dev/null +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr @@ -0,0 +1,65 @@ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ ^^^^^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + | +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10 + | +LL | trait A: Sized { + | - ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + | +LL | trait B { + | - in this trait +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ ^^^^^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + | +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8 + | +LL | trait B { + | - this trait cannot be made into an object... +LL | fn f(a: dyn B) -> dyn B; + | ^ ...because associated function `f` has no `self` parameter +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | fn f(&self, a: dyn B) -> dyn B; + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | fn f(a: dyn B) -> dyn B where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0038`. From 7edbc95c27664428ba22c448ca85ee4bd4de05dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 19 Jan 2024 23:49:40 +0000 Subject: [PATCH 16/17] Update tests after rebase Fix #119652. --- .../object-safety/avoid-ice-on-warning-3.rs | 17 ++ .../avoid-ice-on-warning-3.stderr | 148 ++++++++++++++++++ ...-trait-should-use-self-2021-without-dyn.rs | 4 + ...it-should-use-self-2021-without-dyn.stderr | 75 ++++++++- 4 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 tests/ui/object-safety/avoid-ice-on-warning-3.rs create mode 100644 tests/ui/object-safety/avoid-ice-on-warning-3.stderr diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.rs b/tests/ui/object-safety/avoid-ice-on-warning-3.rs new file mode 100644 index 0000000000000..caaf4d0fd99aa --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.rs @@ -0,0 +1,17 @@ +trait B { fn f(a: A) -> A; } +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +//~| ERROR the trait `A` cannot be made into an object +trait A { fn g(b: B) -> B; } +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +//~| ERROR the trait `B` cannot be made into an object +fn main() {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.stderr new file mode 100644 index 0000000000000..0fc67770b96dd --- /dev/null +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.stderr @@ -0,0 +1,148 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:9:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `B` it is not object safe, so it can't be `dyn` + = note: `#[warn(bare_trait_objects)]` on by default +help: use a new generic type parameter, constrained by `B` + | +LL | trait A { fn g(b: T) -> B; } + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | trait A { fn g(b: impl B) -> B; } + | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:9:25 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | trait A { fn g(b: B) -> impl B; } + | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:1:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `A` it is not object safe, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | trait B { fn f(a: T) -> A; } + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | trait B { fn f(a: impl A) -> A; } + | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:1:25 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | trait B { fn f(a: A) -> impl A; } + | ++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:1:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `A` it is not object safe, so it can't be `dyn` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use a new generic type parameter, constrained by `A` + | +LL | trait B { fn f(a: T) -> A; } + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | trait B { fn f(a: impl A) -> A; } + | ++++ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:1:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:9:14 + | +LL | trait A { fn g(b: B) -> B; } + | - ^ ...because associated function `g` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `g` into a method by giving it a `&self` argument + | +LL | trait A { fn g(&self, b: B) -> B; } + | ++++++ +help: alternatively, consider constraining `g` so it does not apply to trait objects + | +LL | trait A { fn g(b: B) -> B where Self: Sized; } + | +++++++++++++++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/avoid-ice-on-warning-3.rs:9:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `B` it is not object safe, so it can't be `dyn` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use a new generic type parameter, constrained by `B` + | +LL | trait A { fn g(b: T) -> B; } + | ++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | trait A { fn g(b: impl B) -> B; } + | ++++ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/avoid-ice-on-warning-3.rs:9:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/avoid-ice-on-warning-3.rs:1:14 + | +LL | trait B { fn f(a: A) -> A; } + | - ^ ...because associated function `f` has no `self` parameter + | | + | this trait cannot be made into an object... +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | trait B { fn f(&self, a: A) -> A; } + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | trait B { fn f(a: A) -> A where Self: Sized; } + | +++++++++++++++++ + +error: aborting due to 2 previous errors; 6 warnings emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs index 6382480b7e335..f48c3d124ddac 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs @@ -4,11 +4,15 @@ trait A: Sized { fn f(a: A) -> A; //~^ ERROR trait objects must include the `dyn` keyword //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `A` cannot be made into an object } trait B { fn f(a: B) -> B; //~^ ERROR trait objects must include the `dyn` keyword //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `B` cannot be made into an object } trait C { fn f(&self, a: C) -> C; diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr index 1d8ed54804626..73d5a24f83137 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr @@ -1,3 +1,65 @@ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: A) -> A; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `A` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | fn f(a: A) -> A; + | ^ `A` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:3:10 + | +LL | trait A: Sized { + | - ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 + | +LL | trait B { + | - in this trait +LL | fn f(a: B) -> B; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 + | +LL | fn f(a: B) -> B; + | ^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8 + | +LL | trait B { + | - this trait cannot be made into an object... +LL | fn f(a: B) -> B; + | ^ ...because associated function `f` has no `self` parameter +help: consider turning `f` into a method by giving it a `&self` argument + | +LL | fn f(&self, a: B) -> B; + | ++++++ +help: alternatively, consider constraining `f` so it does not apply to trait objects + | +LL | fn f(a: B) -> B where Self: Sized; + | +++++++++++++++++ + error[E0782]: trait objects must include the `dyn` keyword --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 | @@ -33,7 +95,7 @@ LL | fn f(a: A) -> Box; | +++++++ + error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:13 + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 | LL | fn f(a: B) -> B; | ^ @@ -52,7 +114,7 @@ LL | fn f(a: &dyn B) -> B; | ++++ error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:19 + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19 | LL | fn f(a: B) -> B; | ^ @@ -67,7 +129,7 @@ LL | fn f(a: B) -> Box; | +++++++ + error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:20 + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 | LL | fn f(&self, a: C) -> C; | ^ @@ -86,7 +148,7 @@ LL | fn f(&self, a: &dyn C) -> C; | ++++ error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:26 + --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26 | LL | fn f(&self, a: C) -> C; | ^ @@ -100,6 +162,7 @@ help: alternatively, you can return an owned trait object LL | fn f(&self, a: C) -> Box; | +++++++ + -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors -For more information about this error, try `rustc --explain E0782`. +Some errors have detailed explanations: E0038, E0782. +For more information about an error, try `rustc --explain E0038`. From 078a979229b2e68570bf736c0a48be95d1ad41a7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 20 Jan 2024 02:33:49 +0000 Subject: [PATCH 17/17] Don't use ReErased to detect type test promotion failed --- compiler/rustc_borrowck/src/region_infer/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index cbf01feae06a0..89b203f80a435 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; @@ -1145,6 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let ty = ty.fold_with(&mut OpaqueFolder { tcx }); + let mut failed = false; let ty = tcx.fold_regions(ty, |r, _depth| { let r_vid = self.to_region_vid(r); @@ -1160,15 +1161,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) .map(|u_r| ty::Region::new_var(tcx, u_r)) - // In the case of a failure, use `ReErased`. We will eventually - // return `None` in this case. - .unwrap_or(tcx.lifetimes.re_erased) + // In case we could not find a named region to map to, + // we will return `None` below. + .unwrap_or_else(|| { + failed = true; + r + }) }); debug!("try_promote_type_test_subject: folded ty = {:?}", ty); // This will be true if we failed to promote some region. - if ty.has_erased_regions() { + if failed { return None; }