From a82587c1d44ac94fb95fb40989bcc2536fd13b9f Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Sat, 9 Mar 2024 11:42:56 -0500 Subject: [PATCH 1/6] Avoid closing invalid handles --- library/std/src/os/windows/io/handle.rs | 68 +++++++++++++++++-------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 458c3bb036d8d..6461c90de6c19 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -7,7 +7,7 @@ use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; -use crate::mem::forget; +use crate::mem::{forget, ManuallyDrop}; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -91,7 +91,7 @@ pub struct OwnedHandle { #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] -pub struct HandleOrNull(OwnedHandle); +pub struct HandleOrNull(RawHandle); /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses @@ -110,7 +110,7 @@ pub struct HandleOrNull(OwnedHandle); #[repr(transparent)] #[stable(feature = "io_safety", since = "1.63.0")] #[derive(Debug)] -pub struct HandleOrInvalid(OwnedHandle); +pub struct HandleOrInvalid(RawHandle); // The Windows [`HANDLE`] type may be transferred across and shared between // thread boundaries (despite containing a `*mut void`, which in general isn't @@ -163,15 +163,24 @@ impl TryFrom for OwnedHandle { #[inline] fn try_from(handle_or_null: HandleOrNull) -> Result { - let owned_handle = handle_or_null.0; - if owned_handle.handle.is_null() { - // Don't call `CloseHandle`; it'd be harmless, except that it could - // overwrite the `GetLastError` error. - forget(owned_handle); - - Err(NullHandleError(())) + let handle_or_null = ManuallyDrop::new(handle_or_null); + if handle_or_null.is_valid() { + // SAFETY: The handle is not null. + Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_null.0) }) } else { - Ok(owned_handle) + Err(NullHandleError(())) + } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl Drop for HandleOrNull { + #[inline] + fn drop(&mut self) { + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); + } } } } @@ -232,15 +241,24 @@ impl TryFrom for OwnedHandle { #[inline] fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { - let owned_handle = handle_or_invalid.0; - if owned_handle.handle == sys::c::INVALID_HANDLE_VALUE { - // Don't call `CloseHandle`; it'd be harmless, except that it could - // overwrite the `GetLastError` error. - forget(owned_handle); - - Err(InvalidHandleError(())) + let handle_or_invalid = ManuallyDrop::new(handle_or_invalid); + if handle_or_invalid.is_valid() { + // SAFETY: The handle is not invalid. + Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_invalid.0) }) } else { - Ok(owned_handle) + Err(InvalidHandleError(())) + } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl Drop for HandleOrInvalid { + #[inline] + fn drop(&mut self) { + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); + } } } } @@ -333,7 +351,11 @@ impl HandleOrNull { #[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { - Self(OwnedHandle::from_raw_handle(handle)) + Self(handle) + } + + fn is_valid(&self) -> bool { + !self.0.is_null() } } @@ -356,7 +378,11 @@ impl HandleOrInvalid { #[stable(feature = "io_safety", since = "1.63.0")] #[inline] pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { - Self(OwnedHandle::from_raw_handle(handle)) + Self(handle) + } + + fn is_valid(&self) -> bool { + self.0 != sys::c::INVALID_HANDLE_VALUE } } From dd0f41f003d141efec3404e4b750589b348bd5c6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 12 Mar 2024 16:07:01 -0400 Subject: [PATCH 2/6] Fix WF for AsyncFnKindHelper in new trait solver --- compiler/rustc_middle/src/ty/sty.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index cac12e5ee0bb9..11065b2a382be 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2436,8 +2436,9 @@ impl<'tcx> Ty<'tcx> { }, // "Bound" types appear in canonical queries when the - // closure type is not yet known - Bound(..) | Param(_) | Infer(_) => None, + // closure type is not yet known, and `Placeholder` and `Param` + // may be encountered in generic `AsyncFnKindHelper` goals. + Bound(..) | Placeholder(_) | Param(_) | Infer(_) => None, Error(_) => Some(ty::ClosureKind::Fn), From c527ec76ce410c67a5da38f738f23a90e890dca6 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 13 Mar 2024 00:49:51 -0400 Subject: [PATCH 3/6] Improve Step docs --- library/core/src/iter/range.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 68937161e046a..2ecf9ce5b81b3 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -22,7 +22,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 /// /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. -#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[unstable(feature = "step_trait", issue = "42168")] pub trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// @@ -52,15 +52,12 @@ pub trait Step: Clone + PartialOrd + Sized { /// For any `a`, `n`, and `m`: /// /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))` - /// - /// For any `a`, `n`, and `m` where `n + m` does not overflow: - /// - /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)` + /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == try { Step::forward_checked(a, n.checked_add(m)) }` /// /// For any `a` and `n`: /// /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))` - /// * Corollary: `Step::forward_checked(&a, 0) == Some(a)` + /// * Corollary: `Step::forward_checked(a, 0) == Some(a)` fn forward_checked(start: Self, count: usize) -> Option; /// Returns the value that would be obtained by taking the *successor* @@ -106,6 +103,7 @@ pub trait Step: Clone + PartialOrd + Sized { /// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)` /// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`, /// it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`. + /// * Corollary: `Step::forward_unchecked(a, 0)` is always safe. /// /// For any `a` and `n`, where no overflow occurs: /// @@ -128,8 +126,8 @@ pub trait Step: Clone + PartialOrd + Sized { /// /// For any `a` and `n`: /// - /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))` - /// * Corollary: `Step::backward_checked(&a, 0) == Some(a)` + /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(x, 1))` + /// * Corollary: `Step::backward_checked(a, 0) == Some(a)` fn backward_checked(start: Self, count: usize) -> Option; /// Returns the value that would be obtained by taking the *predecessor* @@ -175,6 +173,7 @@ pub trait Step: Clone + PartialOrd + Sized { /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)` /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`, /// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`. + /// * Corollary: `Step::backward_unchecked(a, 0)` is always safe. /// /// For any `a` and `n`, where no overflow occurs: /// From 12cd3220624fe50d039b268cc5ff35c7895ef293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 28 Feb 2024 22:42:31 +0100 Subject: [PATCH 4/6] Make incremental sessions identity no longer depend on the crate names provided by source code --- compiler/rustc_driver_impl/src/lib.rs | 3 +- compiler/rustc_incremental/src/persist/fs.rs | 22 +++--- .../rustc_incremental/src/persist/load.rs | 12 ++-- compiler/rustc_interface/messages.ftl | 3 - compiler/rustc_interface/src/errors.rs | 9 --- compiler/rustc_interface/src/queries.rs | 6 +- compiler/rustc_interface/src/util.rs | 68 ++----------------- compiler/rustc_session/messages.ftl | 3 + compiler/rustc_session/src/errors.rs | 9 ++- compiler/rustc_session/src/output.rs | 65 +++++++++++++++++- 10 files changed, 101 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index c448835413571..938f9f0beaacd 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,7 +28,7 @@ use rustc_errors::{ markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, }; use rustc_feature::find_gated_cfg; -use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; +use rustc_interface::util::{self, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; @@ -37,6 +37,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; +use rustc_session::output::collect_crate_types; use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::FileLoader; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index dd9c16d006a96..1462037c8c8e7 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -110,8 +110,9 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; +use rustc_session::config::CrateType; +use rustc_session::output::{collect_crate_types, find_crate_name}; use rustc_session::{Session, StableCrateId}; -use rustc_span::Symbol; use std::fs as std_fs; use std::io::{self, ErrorKind}; @@ -205,11 +206,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu /// The garbage collection will take care of it. /// /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph -pub(crate) fn prepare_session_directory( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) -> Result<(), ErrorGuaranteed> { +pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuaranteed> { if sess.opts.incremental.is_none() { return Ok(()); } @@ -219,7 +216,7 @@ pub(crate) fn prepare_session_directory( debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess, crate_name, stable_crate_id); + let crate_dir = crate_path(sess); debug!("crate-dir: {}", crate_dir.display()); create_dir(sess, &crate_dir, "crate")?; @@ -604,9 +601,18 @@ fn string_to_timestamp(s: &str) -> Result { Ok(UNIX_EPOCH + duration) } -fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf { +fn crate_path(sess: &Session) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); + let crate_name = find_crate_name(sess, &[]); + let crate_types = collect_crate_types(sess, &[]); + let stable_crate_id = StableCrateId::new( + crate_name, + crate_types.contains(&CrateType::Executable), + sess.opts.cg.metadata.clone(), + sess.cfg_version, + ); + let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE); let crate_name = format!("{crate_name}-{stable_crate_id}"); diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 96bfe766c20f5..357f2ae92d4c3 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -8,8 +8,8 @@ use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; use rustc_session::config::IncrementalStateAssertion; -use rustc_session::{Session, StableCrateId}; -use rustc_span::{ErrorGuaranteed, Symbol}; +use rustc_session::Session; +use rustc_span::ErrorGuaranteed; use std::path::{Path, PathBuf}; use super::data::*; @@ -190,13 +190,9 @@ pub fn load_query_result_cache(sess: &Session) -> Option> { /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a /// new graph to an incremental session directory. -pub fn setup_dep_graph( - sess: &Session, - crate_name: Symbol, - stable_crate_id: StableCrateId, -) -> Result { +pub fn setup_dep_graph(sess: &Session) -> Result { // `load_dep_graph` can only be called after `prepare_session_directory`. - prepare_session_directory(sess, crate_name, stable_crate_id)?; + prepare_session_directory(sess)?; let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess)); diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index bd9fad8b04296..47dfbc1d7fbf1 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -48,6 +48,3 @@ interface_rustc_error_unexpected_annotation = interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` - -interface_unsupported_crate_type_for_target = - dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index a9ab2720d89a5..29294003b8f29 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,7 +1,5 @@ use rustc_macros::Diagnostic; -use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; -use rustc_target::spec::TargetTriple; use std::io; use std::path::Path; @@ -90,13 +88,6 @@ pub struct FailedWritingFile<'a> { #[diag(interface_proc_macro_crate_panic_abort)] pub struct ProcMacroCratePanicAbort; -#[derive(Diagnostic)] -#[diag(interface_unsupported_crate_type_for_target)] -pub struct UnsupportedCrateTypeForTarget<'a> { - pub crate_type: CrateType, - pub target_triple: &'a TargetTriple, -} - #[derive(Diagnostic)] #[diag(interface_multiple_output_types_adaption)] pub struct MultipleOutputTypesAdaption; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c22188226961e..ee677a092e2f1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{GlobalCtxt, TyCtxt}; use rustc_serialize::opaque::FileEncodeResult; use rustc_session::config::{self, CrateType, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; -use rustc_session::output::find_crate_name; +use rustc_session::output::{collect_crate_types, find_crate_name}; use rustc_session::Session; use rustc_span::symbol::sym; use std::any::Any; @@ -128,7 +128,7 @@ impl<'tcx> Queries<'tcx> { // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. let crate_name = find_crate_name(sess, &pre_configured_attrs); - let crate_types = util::collect_crate_types(sess, &pre_configured_attrs); + let crate_types = collect_crate_types(sess, &pre_configured_attrs); let stable_crate_id = StableCrateId::new( crate_name, crate_types.contains(&CrateType::Executable), @@ -136,7 +136,7 @@ impl<'tcx> Queries<'tcx> { sess.cfg_version, ); let outputs = util::build_output_filenames(&pre_configured_attrs, sess); - let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; + let dep_graph = setup_dep_graph(sess)?; let cstore = FreezeLock::new(Box::new(CStore::new( self.compiler.codegen_backend.metadata_loader(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 829b00aabc126..7d48f90db3625 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -7,14 +7,15 @@ use rustc_data_structures::sync; use rustc_metadata::{load_symbol_from_dylib, DylibError}; use rustc_parse::validate_attr; use rustc_session as session; -use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes}; +use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer}; -use rustc_session::{filesearch, output, Session}; +use rustc_session::{filesearch, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_target::spec::Target; +use session::output::{categorize_crate_type, CRATE_TYPES}; use session::EarlyDiagCtxt; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; @@ -399,67 +400,6 @@ pub(crate) fn check_attr_crate_type( } } -const CRATE_TYPES: &[(Symbol, CrateType)] = &[ - (sym::rlib, CrateType::Rlib), - (sym::dylib, CrateType::Dylib), - (sym::cdylib, CrateType::Cdylib), - (sym::lib, config::default_lib_output()), - (sym::staticlib, CrateType::Staticlib), - (sym::proc_dash_macro, CrateType::ProcMacro), - (sym::bin, CrateType::Executable), -]; - -fn categorize_crate_type(s: Symbol) -> Option { - Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1) -} - -pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { - // If we're generating a test executable, then ignore all other output - // styles at all other locations - if session.opts.test { - return vec![CrateType::Executable]; - } - - // Only check command line flags if present. If no types are specified by - // command line, then reuse the empty `base` Vec to hold the types that - // will be found in crate attributes. - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - let mut base = session.opts.crate_types.clone(); - if base.is_empty() { - let attr_types = attrs.iter().filter_map(|a| { - if a.has_name(sym::crate_type) - && let Some(s) = a.value_str() - { - categorize_crate_type(s) - } else { - None - } - }); - base.extend(attr_types); - if base.is_empty() { - base.push(output::default_output_for_target(session)); - } else { - base.sort(); - base.dedup(); - } - } - - base.retain(|crate_type| { - if output::invalid_output_for_target(session, *crate_type) { - session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { - crate_type: *crate_type, - target_triple: &session.opts.target_triple, - }); - false - } else { - true - } - }); - - base -} - fn multiple_output_types_to_stdout( output_types: &OutputTypes, single_output_file_is_stdout: bool, diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index af8c962a2ed6a..42c681e496174 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -111,4 +111,7 @@ session_unleashed_feature_help_unnamed = skipping check that does not even have session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` +session_unsupported_crate_type_for_target = + dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` + session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 5f04915a9e755..d523da1ad7e38 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -10,7 +10,7 @@ use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; -use crate::parse::ParseSess; +use crate::{config::CrateType, parse::ParseSess}; pub struct FeatureGateError { pub span: MultiSpan, @@ -345,6 +345,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported { pub span: Span, } +#[derive(Diagnostic)] +#[diag(session_unsupported_crate_type_for_target)] +pub struct UnsupportedCrateTypeForTarget<'a> { + pub crate_type: CrateType, + pub target_triple: &'a TargetTriple, +} + pub fn report_lit_error( psess: &ParseSess, err: LitError, diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 74d26237f2463..35cd3cbab66ce 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,7 +1,7 @@ //! Related to out filenames of compilation (e.g. binaries). -use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; +use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType}; use crate::errors::{ - CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, InvalidCharacterInCrateName, InvalidCrateNameHelp, }; use crate::Session; @@ -200,3 +200,64 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool false } + +pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[ + (sym::rlib, CrateType::Rlib), + (sym::dylib, CrateType::Dylib), + (sym::cdylib, CrateType::Cdylib), + (sym::lib, config::default_lib_output()), + (sym::staticlib, CrateType::Staticlib), + (sym::proc_dash_macro, CrateType::ProcMacro), + (sym::bin, CrateType::Executable), +]; + +pub fn categorize_crate_type(s: Symbol) -> Option { + Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1) +} + +pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { + // If we're generating a test executable, then ignore all other output + // styles at all other locations + if session.opts.test { + return vec![CrateType::Executable]; + } + + // Only check command line flags if present. If no types are specified by + // command line, then reuse the empty `base` Vec to hold the types that + // will be found in crate attributes. + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + let mut base = session.opts.crate_types.clone(); + if base.is_empty() { + let attr_types = attrs.iter().filter_map(|a| { + if a.has_name(sym::crate_type) + && let Some(s) = a.value_str() + { + categorize_crate_type(s) + } else { + None + } + }); + base.extend(attr_types); + if base.is_empty() { + base.push(default_output_for_target(session)); + } else { + base.sort(); + base.dedup(); + } + } + + base.retain(|crate_type| { + if invalid_output_for_target(session, *crate_type) { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { + crate_type: *crate_type, + target_triple: &session.opts.target_triple, + }); + false + } else { + true + } + }); + + base +} From 1a81a941ad62f6a619789eb67903121622488209 Mon Sep 17 00:00:00 2001 From: surechen Date: Mon, 11 Mar 2024 22:39:02 +0800 Subject: [PATCH 5/6] fixes #121331 --- compiler/rustc_lint_defs/src/builtin.rs | 1 + compiler/rustc_resolve/src/check_unused.rs | 60 +++++++++++++++++-- compiler/rustc_resolve/src/imports.rs | 11 ++-- compiler/rustc_resolve/src/late.rs | 29 +++++---- compiler/rustc_resolve/src/lib.rs | 7 ++- tests/ui/lint/lint-qualification.fixed | 7 ++- tests/ui/lint/lint-qualification.rs | 5 +- tests/ui/lint/lint-qualification.stderr | 30 +++++----- ...necessary-qualification-issue-121331.fixed | 50 ++++++++++++++++ ...-unnecessary-qualification-issue-121331.rs | 50 ++++++++++++++++ ...ecessary-qualification-issue-121331.stderr | 31 ++++++++++ ...lid-unused-qualifications-suggestion.fixed | 11 ++++ ...nvalid-unused-qualifications-suggestion.rs | 11 ++++ ...id-unused-qualifications-suggestion.stderr | 2 +- .../unused-qualifications-suggestion.fixed | 2 + .../unused-qualifications-suggestion.rs | 2 + .../unused-qualifications-suggestion.stderr | 2 +- 17 files changed, 269 insertions(+), 42 deletions(-) create mode 100644 tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed create mode 100644 tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs create mode 100644 tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f2560b35aa2e1..c209f2772ff48 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -556,6 +556,7 @@ declare_lint! { /// fn main() { /// use foo::bar; /// foo::bar(); + /// bar(); /// } /// ``` /// diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index bf1ea2e270932..f6004fed8284e 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -23,18 +23,19 @@ // - `check_unused` finally emits the diagnostics based on the data generated // in the last step -use crate::imports::ImportKind; +use crate::imports::{Import, ImportKind}; use crate::module_to_string; use crate::Resolver; -use crate::NameBindingKind; +use crate::{LexicalScopeBinding, NameBindingKind}; use rustc_ast as ast; use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; use rustc_hir::def::{DefKind, Res}; -use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS}; +use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES}; +use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS}; use rustc_session::lint::BuiltinLintDiag; use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; @@ -514,8 +515,59 @@ impl Resolver<'_, '_> { } } + let mut redundant_imports = UnordSet::default(); for import in check_redundant_imports { - self.check_for_redundant_imports(import); + if self.check_for_redundant_imports(import) + && let Some(id) = import.id() + { + redundant_imports.insert(id); + } + } + + // The lint fixes for unused_import and unnecessary_qualification may conflict. + // Deleting both unused imports and unnecessary segments of an item may result + // in the item not being found. + for unn_qua in &self.potentially_unnecessary_qualifications { + if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding + && let NameBindingKind::Import { import, .. } = name_binding.kind + && (is_unused_import(import, &unused_imports) + || is_redundant_import(import, &redundant_imports)) + { + continue; + } + + self.lint_buffer.buffer_lint_with_diagnostic( + UNUSED_QUALIFICATIONS, + unn_qua.node_id, + unn_qua.path_span, + "unnecessary qualification", + BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span }, + ); + } + + fn is_redundant_import( + import: Import<'_>, + redundant_imports: &UnordSet, + ) -> bool { + if let Some(id) = import.id() + && redundant_imports.contains(&id) + { + return true; + } + false + } + + fn is_unused_import( + import: Import<'_>, + unused_imports: &FxIndexMap, + ) -> bool { + if let Some(unused_import) = unused_imports.get(&import.root_id) + && let Some(id) = import.id() + && unused_import.unused.contains(&id) + { + return true; + } + false } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index ea08041f2aadd..9bf3e9ccabdf1 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1306,7 +1306,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) { + pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) -> bool { // This function is only called for single imports. let ImportKind::Single { source, target, ref source_bindings, ref target_bindings, id, .. @@ -1317,12 +1317,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Skip if the import is of the form `use source as target` and source != target. if source != target { - return; + return false; } // Skip if the import was produced by a macro. if import.parent_scope.expansion != LocalExpnId::ROOT { - return; + return false; } // Skip if we are inside a named module (in contrast to an anonymous @@ -1332,7 +1332,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if import.used.get() == Some(Used::Other) || self.effective_visibilities.is_exported(self.local_def_id(id)) { - return; + return false; } let mut is_redundant = true; @@ -1375,7 +1375,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("the item `{source}` is imported redundantly"), BuiltinLintDiag::RedundantImport(redundant_spans, source), ); + return true; } + + false } fn resolve_glob_import(&mut self, import: Import<'a>) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a996188db0229..c9b5c659f0f47 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -580,6 +580,15 @@ impl MaybeExported<'_> { } } +/// Used for recording UnnecessaryQualification. +#[derive(Debug)] +pub(crate) struct UnnecessaryQualification<'a> { + pub binding: LexicalScopeBinding<'a>, + pub node_id: NodeId, + pub path_span: Span, + pub removal_span: Span, +} + #[derive(Default)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. @@ -4654,20 +4663,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let ns = if i + 1 == path.len() { ns } else { TypeNS }; let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?; let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?; - - (res == binding.res()).then_some(seg) + (res == binding.res()).then_some((seg, binding)) }); - if let Some(unqualified) = unqualified { - self.r.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::UNUSED_QUALIFICATIONS, - finalize.node_id, - finalize.path_span, - "unnecessary qualification", - lint::BuiltinLintDiag::UnusedQualifications { - removal_span: path[0].ident.span.until(unqualified.ident.span), - }, - ); + if let Some((seg, binding)) = unqualified { + self.r.potentially_unnecessary_qualifications.push(UnnecessaryQualification { + binding, + node_id: finalize.node_id, + path_span: finalize.path_span, + removal_span: path[0].ident.span.until(seg.ident.span), + }); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ccb67ea78cfdb..dfc2d029d4cfd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -68,7 +68,7 @@ use std::fmt; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportData, ImportKind, NameResolution}; -use late::{HasGenericParams, PathSource, PatternSource}; +use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::effective_visibilities::EffectiveVisibilitiesVisitor; @@ -372,7 +372,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that /// items are visible in their whole block, while `Res`es only from the place they are defined /// forward. -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] enum LexicalScopeBinding<'a> { Item(NameBinding<'a>), Res(Res), @@ -1105,6 +1105,8 @@ pub struct Resolver<'a, 'tcx> { potentially_unused_imports: Vec>, + potentially_unnecessary_qualifications: Vec>, + /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility @@ -1464,6 +1466,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), potentially_unused_imports: Vec::new(), + potentially_unnecessary_qualifications: Default::default(), struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed index 2b1f8b591752a..6fe6ba2792fe6 100644 --- a/tests/ui/lint/lint-qualification.fixed +++ b/tests/ui/lint/lint-qualification.fixed @@ -1,5 +1,6 @@ //@ run-rustfix #![deny(unused_qualifications)] +#![deny(unused_imports)] #![allow(deprecated, dead_code)] mod foo { @@ -21,8 +22,10 @@ fn main() { //~^ ERROR: unnecessary qualification //~| ERROR: unnecessary qualification - use std::fmt; - let _: fmt::Result = Ok(()); //~ ERROR: unnecessary qualification + + //~^ ERROR: unused import: `std::fmt` + let _: std::fmt::Result = Ok(()); + // don't report unnecessary qualification because fix(#122373) for issue #121331 let _ = ::default(); // issue #121999 //~^ ERROR: unnecessary qualification diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs index 002fdbf7724a7..19d339b006c9a 100644 --- a/tests/ui/lint/lint-qualification.rs +++ b/tests/ui/lint/lint-qualification.rs @@ -1,5 +1,6 @@ //@ run-rustfix #![deny(unused_qualifications)] +#![deny(unused_imports)] #![allow(deprecated, dead_code)] mod foo { @@ -22,7 +23,9 @@ fn main() { //~| ERROR: unnecessary qualification use std::fmt; - let _: std::fmt::Result = Ok(()); //~ ERROR: unnecessary qualification + //~^ ERROR: unused import: `std::fmt` + let _: std::fmt::Result = Ok(()); + // don't report unnecessary qualification because fix(#122373) for issue #121331 let _ = ::default(); // issue #121999 //~^ ERROR: unnecessary qualification diff --git a/tests/ui/lint/lint-qualification.stderr b/tests/ui/lint/lint-qualification.stderr index 8dddcf23f7575..9e5c9b2df13f1 100644 --- a/tests/ui/lint/lint-qualification.stderr +++ b/tests/ui/lint/lint-qualification.stderr @@ -1,5 +1,5 @@ error: unnecessary qualification - --> $DIR/lint-qualification.rs:11:5 + --> $DIR/lint-qualification.rs:12:5 | LL | foo::bar(); | ^^^^^^^^ @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:12:5 + --> $DIR/lint-qualification.rs:13:5 | LL | crate::foo::bar(); | ^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:17:13 + --> $DIR/lint-qualification.rs:18:13 | LL | let _ = std::string::String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = String::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:18:13 + --> $DIR/lint-qualification.rs:19:13 | LL | let _ = ::std::env::current_dir(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + let _ = std::env::current_dir(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:12 + --> $DIR/lint-qualification.rs:21:12 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL + let _: Vec = std::vec::Vec::::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:36 + --> $DIR/lint-qualification.rs:21:36 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,20 +75,20 @@ LL - let _: std::vec::Vec = std::vec::Vec::::new(); LL + let _: std::vec::Vec = Vec::::new(); | -error: unnecessary qualification - --> $DIR/lint-qualification.rs:25:12 - | -LL | let _: std::fmt::Result = Ok(()); - | ^^^^^^^^^^^^^^^^ +error: unused import: `std::fmt` + --> $DIR/lint-qualification.rs:25:9 | -help: remove the unnecessary path segments +LL | use std::fmt; + | ^^^^^^^^ | -LL - let _: std::fmt::Result = Ok(()); -LL + let _: fmt::Result = Ok(()); +note: the lint level is defined here + --> $DIR/lint-qualification.rs:3:9 | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ error: unnecessary qualification - --> $DIR/lint-qualification.rs:27:13 + --> $DIR/lint-qualification.rs:30:13 | LL | let _ = ::default(); // issue #121999 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed new file mode 100644 index 0000000000000..d554bbfcc98c9 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed @@ -0,0 +1,50 @@ +//@ run-rustfix +//@ edition:2021 +#![deny(unused_qualifications)] +#![deny(unused_imports)] +#![feature(coroutines, coroutine_trait)] + +use std::ops::{ + Coroutine, + CoroutineState::{self}, + //~^ ERROR unused import: `*` +}; +use std::pin::Pin; + +#[allow(dead_code)] +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Coroutine<(), Yield = ()> + Unpin, +{ + loop { + match Pin::new(&mut t).resume(()) { + CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + CoroutineState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } +} + + +mod foo { + pub fn bar() {} +} + +pub fn main() { + + use foo::bar; + bar(); + //~^ ERROR unnecessary qualification + bar(); + + // The item `use std::string::String` is imported redundantly. + // Suppress `unused_imports` reporting, otherwise the fixed file will report an error + #[allow(unused_imports)] + use std::string::String; + let s = String::new(); + let y = std::string::String::new(); + // unnecessary qualification + println!("{} {}", s, y); + +} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs new file mode 100644 index 0000000000000..4d79f5ab74530 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs @@ -0,0 +1,50 @@ +//@ run-rustfix +//@ edition:2021 +#![deny(unused_qualifications)] +#![deny(unused_imports)] +#![feature(coroutines, coroutine_trait)] + +use std::ops::{ + Coroutine, + CoroutineState::{self, *}, + //~^ ERROR unused import: `*` +}; +use std::pin::Pin; + +#[allow(dead_code)] +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Coroutine<(), Yield = ()> + Unpin, +{ + loop { + match Pin::new(&mut t).resume(()) { + CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + CoroutineState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } +} + + +mod foo { + pub fn bar() {} +} + +pub fn main() { + + use foo::bar; + foo::bar(); + //~^ ERROR unnecessary qualification + bar(); + + // The item `use std::string::String` is imported redundantly. + // Suppress `unused_imports` reporting, otherwise the fixed file will report an error + #[allow(unused_imports)] + use std::string::String; + let s = String::new(); + let y = std::string::String::new(); + // unnecessary qualification + println!("{} {}", s, y); + +} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr new file mode 100644 index 0000000000000..52ed13ea150d7 --- /dev/null +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr @@ -0,0 +1,31 @@ +error: unused import: `*` + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:9:28 + | +LL | CoroutineState::{self, *}, + | ^ + | +note: the lint level is defined here + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:4:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unnecessary qualification + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:37:5 + | +LL | foo::bar(); + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-unnecessary-qualification-issue-121331.rs:3:9 + | +LL | #![deny(unused_qualifications)] + | ^^^^^^^^^^^^^^^^^^^^^ +help: remove the unnecessary path segments + | +LL - foo::bar(); +LL + bar(); + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed index 8a67b20eec11d..d95faef8ac44b 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed @@ -18,6 +18,16 @@ impl Index for A { } } +// This is used to make `use std::ops::Index;` not unused_import. +// details in fix(#122373) for issue #121331 +pub struct C; +impl Index for C { + type Output = (); + fn index(&self, _: str) -> &Self::Output { + &() + } +} + mod inner { pub trait Trait {} } @@ -29,4 +39,5 @@ use inner::Trait; impl Trait for () {} //~^ ERROR unnecessary qualification +impl Trait for A {} fn main() {} diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs index 528edb331cf55..0eee8f71ad4e1 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs @@ -18,6 +18,16 @@ impl ops::Index for A { } } +// This is used to make `use std::ops::Index;` not unused_import. +// details in fix(#122373) for issue #121331 +pub struct C; +impl Index for C { + type Output = (); + fn index(&self, _: str) -> &Self::Output { + &() + } +} + mod inner { pub trait Trait {} } @@ -29,4 +39,5 @@ use inner::Trait; impl inner::Trait for () {} //~^ ERROR unnecessary qualification +impl Trait for A {} fn main() {} diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr index bcda721071235..e105b754b7195 100644 --- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr @@ -16,7 +16,7 @@ LL + impl Index for A { | error: unnecessary qualification - --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6 + --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:39:6 | LL | impl inner::Trait for () {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/resolve/unused-qualifications-suggestion.fixed b/tests/ui/resolve/unused-qualifications-suggestion.fixed index 6935f611b361f..22e0daea46764 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.fixed +++ b/tests/ui/resolve/unused-qualifications-suggestion.fixed @@ -16,8 +16,10 @@ fn main() { use foo::bar; bar(); //~^ ERROR unnecessary qualification + bar(); use baz::qux::quux; quux(); //~^ ERROR unnecessary qualification + quux(); } diff --git a/tests/ui/resolve/unused-qualifications-suggestion.rs b/tests/ui/resolve/unused-qualifications-suggestion.rs index b3fe04ff0ea4b..89516c1344a9e 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.rs +++ b/tests/ui/resolve/unused-qualifications-suggestion.rs @@ -16,8 +16,10 @@ fn main() { use foo::bar; foo::bar(); //~^ ERROR unnecessary qualification + bar(); use baz::qux::quux; baz::qux::quux(); //~^ ERROR unnecessary qualification + quux(); } diff --git a/tests/ui/resolve/unused-qualifications-suggestion.stderr b/tests/ui/resolve/unused-qualifications-suggestion.stderr index e3dac37fc6e22..5b71ba9e2223c 100644 --- a/tests/ui/resolve/unused-qualifications-suggestion.stderr +++ b/tests/ui/resolve/unused-qualifications-suggestion.stderr @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/unused-qualifications-suggestion.rs:21:5 + --> $DIR/unused-qualifications-suggestion.rs:22:5 | LL | baz::qux::quux(); | ^^^^^^^^^^^^^^ From da8a8c9223722e17cc0173ce9490076b4a6d263d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Mar 2024 08:09:21 +0100 Subject: [PATCH 6/6] preserve span when evaluating mir::ConstOperand --- .../src/dataflow_const_prop.rs | 4 +- .../rustc_mir_transform/src/jump_threading.rs | 3 +- compiler/rustc_monomorphize/src/collector.rs | 7 ++- compiler/rustc_smir/src/rustc_smir/builder.rs | 2 +- .../ui/consts/assoc_const_generic_impl.stderr | 6 +++ .../index-out-of-bounds-never-type.stderr | 6 +++ .../const-eval/issue-50814-2.mir-opt.stderr | 46 +++++++++++++++++++ .../const-eval/issue-50814-2.normal.stderr | 14 ++++++ tests/ui/consts/const-eval/issue-50814.stderr | 14 ++++++ tests/ui/consts/const-eval/issue-85155.stderr | 8 ++++ .../unused-broken-const-late.stderr | 6 +++ .../const-expr-generic-err.stderr | 20 ++++++++ tests/ui/inline-const/required-const.stderr | 6 +++ 13 files changed, 137 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index c3e932fe18726..f456196b2822d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -393,7 +393,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) { + if let Ok(constant) = + self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None) + { self.assign_constant(state, place, constant, &[]); } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index ad8f21ffbdaa1..6629face94041 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -416,7 +416,8 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let constant = self.ecx.eval_mir_constant(&constant.const_, None, None).ok()?; + let constant = + self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None).ok()?; self.process_constant(bb, lhs, constant, state); } // Transfer the conditions on the copied rhs. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 33a446eb55a1a..0fc6c1019e596 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -825,14 +825,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { let const_ = self.monomorphize(constant.const_); let param_env = ty::ParamEnv::reveal_all(); - let val = match const_.eval(self.tcx, param_env, None) { + let val = match const_.eval(self.tcx, param_env, Some(constant.span)) { Ok(v) => v, - Err(ErrorHandled::Reported(..)) => return, Err(ErrorHandled::TooGeneric(..)) => span_bug!( self.body.source_info(location).span, "collection encountered polymorphic constant: {:?}", const_ ), + Err(err @ ErrorHandled::Reported(..)) => { + err.emit_note(self.tcx); + return; + } }; collect_const_value(self.tcx, val, self.output); MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location)); diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 039bdec4c78a6..a13262cdcc494 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -56,7 +56,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) { let const_ = self.monomorphize(constant.const_); - let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) { + let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) { Ok(v) => v, Err(mir::interpret::ErrorHandled::Reported(..)) => return, Err(mir::interpret::ErrorHandled::TooGeneric(..)) => { diff --git a/tests/ui/consts/assoc_const_generic_impl.stderr b/tests/ui/consts/assoc_const_generic_impl.stderr index d826972ce9f5a..4521950839670 100644 --- a/tests/ui/consts/assoc_const_generic_impl.stderr +++ b/tests/ui/consts/assoc_const_generic_impl.stderr @@ -4,6 +4,12 @@ error[E0080]: evaluation of `::I_AM_ZERO_SIZED` failed LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4 +note: erroneous constant encountered + --> $DIR/assoc_const_generic_impl.rs:11:9 + | +LL | Self::I_AM_ZERO_SIZED; + | ^^^^^^^^^^^^^^^^^^^^^ + note: the above error was encountered while instantiating `fn ::requires_zero_size` --> $DIR/assoc_const_generic_impl.rs:18:5 | diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index 4e7ef52f674af..7facb2d1a5ca2 100644 --- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -4,6 +4,12 @@ error[E0080]: evaluation of `PrintName::<()>::VOID` failed LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; | ^^^^^ index out of bounds: the length is 0 but the index is 0 +note: erroneous constant encountered + --> $DIR/index-out-of-bounds-never-type.rs:16:13 + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ + note: the above error was encountered while instantiating `fn f::<()>` --> $DIR/index-out-of-bounds-never-type.rs:20:5 | diff --git a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr index 7e764ca72390d..2de68d3fee9e0 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr @@ -10,6 +10,52 @@ note: erroneous constant encountered LL | & as Foo>::BAR | ^^^^^^^^^^^^^^^^^^^^^ +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:5 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:5 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:5 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:5 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:6 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:6 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr index f552c8fde5bce..4a7dfb1930443 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr @@ -10,6 +10,20 @@ note: erroneous constant encountered LL | & as Foo>::BAR | ^^^^^^^^^^^^^^^^^^^^^ +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:5 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/issue-50814-2.rs:20:6 + | +LL | & as Foo>::BAR + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + note: the above error was encountered while instantiating `fn foo::<()>` --> $DIR/issue-50814-2.rs:32:22 | diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr index 8d01816140152..fe0e25b820f58 100644 --- a/tests/ui/consts/const-eval/issue-50814.stderr +++ b/tests/ui/consts/const-eval/issue-50814.stderr @@ -26,6 +26,20 @@ LL | &Sum::::MAX | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +note: erroneous constant encountered + --> $DIR/issue-50814.rs:21:5 + | +LL | &Sum::::MAX + | ^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/issue-50814.rs:21:6 + | +LL | &Sum::::MAX + | ^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + note: the above error was encountered while instantiating `fn foo::` --> $DIR/issue-50814.rs:26:5 | diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr index a88e959a8a659..99836a3fac6d5 100644 --- a/tests/ui/consts/const-eval/issue-85155.stderr +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -4,6 +4,14 @@ error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2, LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero +note: erroneous constant encountered + --> $DIR/auxiliary/post_monomorphization_error.rs:19:5 + | +LL | static_assert_imm1!(IMM1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this note originates in the macro `static_assert_imm1` (in Nightly builds, run with -Z macro-backtrace for more info) + note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2>` --> $DIR/issue-85155.rs:19:5 | diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.stderr b/tests/ui/consts/const-eval/unused-broken-const-late.stderr index c2cf2f3813c5e..2ff6b27a21616 100644 --- a/tests/ui/consts/const-eval/unused-broken-const-late.stderr +++ b/tests/ui/consts/const-eval/unused-broken-const-late.stderr @@ -6,6 +6,12 @@ LL | const VOID: () = panic!(); | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) +note: erroneous constant encountered + --> $DIR/unused-broken-const-late.rs:15:17 + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index fc0b6cc445164..7331c7f18e976 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -6,6 +6,12 @@ LL | const { assert!(std::mem::size_of::() == 0); } | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) +note: erroneous constant encountered + --> $DIR/const-expr-generic-err.rs:5:5 + | +LL | const { assert!(std::mem::size_of::() == 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + note: the above error was encountered while instantiating `fn foo::` --> $DIR/const-expr-generic-err.rs:13:5 | @@ -18,6 +24,20 @@ error[E0080]: evaluation of `bar::<0>::{constant#0}` failed LL | const { N - 1 } | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow +note: erroneous constant encountered + --> $DIR/const-expr-generic-err.rs:9:5 + | +LL | const { N - 1 } + | ^^^^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/const-expr-generic-err.rs:9:5 + | +LL | const { N - 1 } + | ^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + note: the above error was encountered while instantiating `fn bar::<0>` --> $DIR/const-expr-generic-err.rs:14:5 | diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr index cd86020184dda..2a13d18547c54 100644 --- a/tests/ui/inline-const/required-const.stderr +++ b/tests/ui/inline-const/required-const.stderr @@ -6,6 +6,12 @@ LL | const { panic!() } | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) +note: erroneous constant encountered + --> $DIR/required-const.rs:7:9 + | +LL | const { panic!() } + | ^^^^^^^^^^^^^^^^^^ + error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`.