diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 12ff4be4f1e8c..56978bcbed8e5 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -6,7 +6,7 @@ name: Post merge analysis on: push: branches: - - master + - main jobs: analysis: diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 9e32a85e361a5..8d84e380ab793 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -3465,14 +3465,9 @@ impl Drop for Buffy { pub fn stderr_destination(color: ColorConfig) -> Destination { let buffer_writer = std::io::stderr(); - let choice = color.to_color_choice(); // We need to resolve `ColorChoice::Auto` before `Box`ing since // `ColorChoice::Auto` on `dyn Write` will always resolve to `Never` - let choice = if matches!(choice, ColorChoice::Auto) { - AutoStream::choice(&buffer_writer) - } else { - choice - }; + let choice = get_stderr_color_choice(color, &buffer_writer); // On Windows we'll be performing global synchronization on the entire // system for emitting rustc errors, so there's no need to buffer // anything. @@ -3487,6 +3482,11 @@ pub fn stderr_destination(color: ColorConfig) -> Destination { } } +pub fn get_stderr_color_choice(color: ColorConfig, stderr: &std::io::Stderr) -> ColorChoice { + let choice = color.to_color_choice(); + if matches!(choice, ColorChoice::Auto) { AutoStream::choice(stderr) } else { choice } +} + /// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead. /// /// See #36178. diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 82f9dfe4745d2..d469b6aa075ea 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -45,6 +45,9 @@ struct Access { /// When we encounter multiple statements at the same location, we only increase the liveness, /// in order to avoid false positives. live: bool, + /// Is this a direct access to the place itself, no projections, or to a field? + /// This helps distinguish `x = ...` from `x.field = ...` + is_direct: bool, } #[tracing::instrument(level = "debug", skip(tcx), ret)] @@ -689,15 +692,17 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { |place: Place<'tcx>, kind, source_info: SourceInfo, live: &DenseBitSet| { if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) { if !is_indirect(extra_projections) { + let is_direct = extra_projections.is_empty(); match assignments[index].entry(source_info) { IndexEntry::Vacant(v) => { - let access = Access { kind, live: live.contains(index) }; + let access = Access { kind, live: live.contains(index), is_direct }; v.insert(access); } IndexEntry::Occupied(mut o) => { // There were already a sighting. Mark this statement as live if it // was, to avoid false positives. o.get_mut().live |= live.contains(index); + o.get_mut().is_direct &= is_direct; } } } @@ -781,7 +786,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { continue; }; let source_info = body.local_decls[place.local].source_info; - let access = Access { kind, live: live.contains(index) }; + let access = Access { kind, live: live.contains(index), is_direct: true }; assignments[index].insert(source_info, access); } } @@ -875,6 +880,33 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { dead_captures } + /// Check if a local is referenced in any reachable basic block. + /// Variables in unreachable code (e.g., after `todo!()`) should not trigger unused warnings. + fn is_local_in_reachable_code(&self, local: Local) -> bool { + struct LocalVisitor { + target_local: Local, + found: bool, + } + + impl<'tcx> Visitor<'tcx> for LocalVisitor { + fn visit_local(&mut self, local: Local, _context: PlaceContext, _location: Location) { + if local == self.target_local { + self.found = true; + } + } + } + + let mut visitor = LocalVisitor { target_local: local, found: false }; + for (bb, bb_data) in traversal::postorder(self.body) { + visitor.visit_basic_block_data(bb, bb_data); + if visitor.found { + return true; + } + } + + false + } + /// Report fully unused locals, and forget the corresponding assignments. fn report_fully_unused(&mut self) { let tcx = self.tcx; @@ -928,6 +960,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let statements = &mut self.assignments[index]; if statements.is_empty() { + if !self.is_local_in_reachable_code(local) { + continue; + } + let sugg = if from_macro { errors::UnusedVariableSugg::NoSugg { span: def_span, name } } else { @@ -977,8 +1013,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { self.checked_places, self.body, ) { - statements.clear(); - continue; + statements.retain(|_, access| access.is_direct); + if statements.is_empty() { + continue; + } } let typo = maybe_suggest_typo(); @@ -1049,26 +1087,28 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let Some((name, decl_span)) = self.checked_places.names[index] else { continue }; - // We have outstanding assignments and with non-trivial drop. - // This is probably a drop-guard, so we do not issue a warning there. - if maybe_drop_guard( + let is_maybe_drop_guard = maybe_drop_guard( tcx, self.typing_env, index, &self.ever_dropped, self.checked_places, self.body, - ) { - continue; - } + ); // We probed MIR in reverse order for dataflow. // We revert the vector to give a consistent order to the user. - for (source_info, Access { live, kind }) in statements.into_iter().rev() { + for (source_info, Access { live, kind, is_direct }) in statements.into_iter().rev() { if live { continue; } + // If this place was dropped and has non-trivial drop, + // skip reporting field assignments. + if !is_direct && is_maybe_drop_guard { + continue; + } + // Report the dead assignment. let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else { continue; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 373819d96f4a9..4cabec1469db9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,11 +1,12 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use std::collections::hash_set; use std::path::PathBuf; use rustc_abi::ExternAbi; use rustc_ast::ast::LitKind; use rustc_ast::{LitIntType, TraitObjectSyntax}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ @@ -1927,11 +1928,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if self.tcx.visibility(did).is_accessible_from(body_def_id, self.tcx) { // don't suggest foreign `#[doc(hidden)]` types if !did.is_local() { - while let Some(parent) = parent_map.get(&did) { + let mut previously_seen_dids: FxHashSet = Default::default(); + previously_seen_dids.insert(did); + while let Some(&parent) = parent_map.get(&did) + && let hash_set::Entry::Vacant(v) = + previously_seen_dids.entry(parent) + { if self.tcx.is_doc_hidden(did) { return false; } - did = *parent; + v.insert(); + did = parent; } } true diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index fc0cf8f140a70..e575dddf6a2cb 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,6 +20,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(default_field_values)] +#![feature(hash_set_entry)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index ca5b46c9b0fd0..a145bee251ae6 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2414,7 +2414,7 @@ impl Default for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.iter().eq(other) + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } diff --git a/library/alloctests/tests/collections/eq_diff_len.rs b/library/alloctests/tests/collections/eq_diff_len.rs new file mode 100644 index 0000000000000..ee1e294d37c67 --- /dev/null +++ b/library/alloctests/tests/collections/eq_diff_len.rs @@ -0,0 +1,96 @@ +//! Regression tests which fail if some collections' `PartialEq::eq` impls compare +//! elements when the collections have different sizes. +//! This behavior is not guaranteed either way, so regressing these tests is fine +//! if it is done on purpose. +use std::cmp::Ordering; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList}; + +/// This intentionally has a panicking `PartialEq` impl, to test that various +/// collections' `PartialEq` impls don't actually compare elements if their sizes +/// are unequal. +/// +/// This is not advisable in normal code. +#[derive(Debug, Clone, Copy, Hash)] +struct Evil; + +impl PartialEq for Evil { + fn eq(&self, _: &Self) -> bool { + panic!("Evil::eq is evil"); + } +} +impl Eq for Evil {} + +impl PartialOrd for Evil { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Evil { + fn cmp(&self, _: &Self) -> Ordering { + // Constructing a `BTreeSet`/`BTreeMap` uses `cmp` on the elements, + // but comparing it with with `==` uses `eq` on the elements, + // so Evil::cmp doesn't need to be evil. + Ordering::Equal + } +} + +// check Evil works +#[test] +#[should_panic = "Evil::eq is evil"] +fn evil_eq_works() { + let v1 = vec![Evil]; + let v2 = vec![Evil]; + + _ = v1 == v2; +} + +// check various containers don't compare if their sizes are different + +#[test] +fn vec_evil_eq() { + let v1 = vec![Evil]; + let v2 = vec![Evil; 2]; + + assert_eq!(false, v1 == v2); +} + +#[test] +fn hashset_evil_eq() { + let s1 = HashSet::from([(0, Evil)]); + let s2 = HashSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn hashmap_evil_eq() { + let m1 = HashMap::from([(0, Evil)]); + let m2 = HashMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn btreeset_evil_eq() { + let s1 = BTreeSet::from([(0, Evil)]); + let s2 = BTreeSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn btreemap_evil_eq() { + let m1 = BTreeMap::from([(0, Evil)]); + let m2 = BTreeMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn linkedlist_evil_eq() { + let m1 = LinkedList::from([Evil]); + let m2 = LinkedList::from([Evil; 2]); + + assert_eq!(false, m1 == m2); +} diff --git a/library/alloctests/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs index e73f3aaef8c83..2d387f0e77eb5 100644 --- a/library/alloctests/tests/collections/mod.rs +++ b/library/alloctests/tests/collections/mod.rs @@ -1 +1,2 @@ mod binary_heap; +mod eq_diff_len; diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 47516cbc1f4cd..245ab31fa6446 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -123,7 +123,7 @@ pub fn load_job_db(db: &str) -> anyhow::Result { /// modulo certain carve-outs" in [`validate_job_database`]. /// /// This invariant is important to make sure that it's not easily possible (without modifying -/// `citool`) to have PRs with red PR-only CI jobs merged into `master`, causing all subsequent PR +/// `citool`) to have PRs with red PR-only CI jobs merged into `main`, causing all subsequent PR /// CI runs to be red until the cause is fixed. fn register_pr_jobs_as_auto_jobs(db: &mut JobDatabase) -> anyhow::Result<()> { for pr_job in &db.pr_jobs { @@ -273,7 +273,7 @@ pub enum RunType { /// Merge attempt workflow AutoJob, /// Fake job only used for sharing Github Actions cache. - MasterJob, + MainJob, } /// Maximum number of custom try jobs that can be requested in a single @@ -323,7 +323,7 @@ fn calculate_jobs( (jobs, "try", &db.envs.try_env) } RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env), - RunType::MasterJob => return Ok(vec![]), + RunType::MainJob => return Ok(vec![]), }; let jobs = substitute_github_vars(jobs.clone()) .context("Failed to substitute GitHub context variables in jobs")?; @@ -376,7 +376,7 @@ pub fn calculate_job_matrix( eprintln!("Run type: {run_type:?}"); let jobs = calculate_jobs(&run_type, &db, channel)?; - if jobs.is_empty() && !matches!(run_type, RunType::MasterJob) { + if jobs.is_empty() && !matches!(run_type, RunType::MainJob) { return Err(anyhow::anyhow!("Computed job list is empty")); } @@ -384,7 +384,7 @@ pub fn calculate_job_matrix( RunType::PullRequest => "pr", RunType::TryJob { .. } => "try", RunType::AutoJob => "auto", - RunType::MasterJob => "master", + RunType::MainJob => "main", }; eprintln!("Output"); diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 255d39846da1f..4fe9cee900ca6 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -47,7 +47,7 @@ impl GitHubContext { Some(RunType::TryJob { job_patterns: patterns }) } ("push", "refs/heads/auto") => Some(RunType::AutoJob), - ("push", "refs/heads/master") => Some(RunType::MasterJob), + ("push", "refs/heads/main") => Some(RunType::MainJob), _ => None, } } diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs index 24e0b85cab22f..5231d4616e049 100644 --- a/src/ci/citool/tests/jobs.rs +++ b/src/ci/citool/tests/jobs.rs @@ -46,11 +46,11 @@ fn pr_jobs() { } #[test] -fn master_jobs() { - let stdout = get_matrix("push", "commit", "refs/heads/master"); +fn main_jobs() { + let stdout = get_matrix("push", "commit", "refs/heads/main"); insta::assert_snapshot!(stdout, @r#" jobs=[] - run_type=master + run_type=main "#); } diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh index 3b646587dc28d..e38e20d47c3db 100755 --- a/src/ci/scripts/checkout-submodules.sh +++ b/src/ci/scripts/checkout-submodules.sh @@ -17,7 +17,7 @@ ci_dir=$(cd $(dirname $0) && pwd)/.. # On the beta channel we'll be automatically calculating the prerelease version # via the git history, so unshallow our shallow clone from CI. if [ "$(releaseChannel)" = "beta" ]; then - git fetch origin --unshallow beta master + git fetch origin --unshallow beta main fi function fetch_github_commit_archive { diff --git a/src/ci/scripts/verify-backported-commits.sh b/src/ci/scripts/verify-backported-commits.sh index d3da6d1ac915a..e7d2692e1187d 100755 --- a/src/ci/scripts/verify-backported-commits.sh +++ b/src/ci/scripts/verify-backported-commits.sh @@ -1,5 +1,6 @@ #!/bin/bash -# Ensure commits in beta are in master & commits in stable are in beta + master. +# Ensure commits in beta are in the default branch & commits in stable are in beta + the default +# branch. set -euo pipefail IFS=$'\n\t' @@ -19,11 +20,11 @@ verify_backported_commits_main() { fi if [[ $ci_base_branch == "beta" ]]; then - verify_cherries master "$BETA_LIMIT" \ + verify_cherries HEAD "$BETA_LIMIT" \ || exit 1 elif [[ $ci_base_branch == "stable" ]]; then - (verify_cherries master "$STABLE_LIMIT" \ + (verify_cherries HEAD "$STABLE_LIMIT" \ & verify_cherries beta "$STABLE_LIMIT") \ || exit 1 @@ -64,7 +65,7 @@ verify_cherries() { continue fi - if ! is_in_master "$backport_sha"; then + if ! is_in_default_branch "$backport_sha"; then bad_backports+=("$sha") continue fi @@ -85,7 +86,7 @@ verify_cherries() { done echo echo "do not match any commits in \`$1\`. If this was intended, add the text" - echo '\`backport-of: \`' + echo '\`backport-of: \`' echo 'somewhere in the message of each of these commits.' echo failure=1 @@ -101,7 +102,7 @@ verify_cherries() { done echo echo 'have commit messages marked \`backport-of: \`, but the SHA is not in' - echo '\`master\`.' + echo 'the default branch.' echo failure=1 fi @@ -132,11 +133,11 @@ get_backport() { | sed -n '/^.*backport-of:\s\?\([a-f0-9]\+\|nothing\).*/{s//\1/p;q}' } -# Check if a commit is in master. +# Check if a commit is in the default branch. # # $1 = -is_in_master() { - git merge-base --is-ancestor "$1" origin/master 2> /dev/null +is_in_default_branch() { + git merge-base --is-ancestor "$1" origin/HEAD 2> /dev/null } verify_backported_commits_main diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh index edeea20144be3..9a9e713243d76 100755 --- a/src/ci/scripts/verify-channel.sh +++ b/src/ci/scripts/verify-channel.sh @@ -1,7 +1,7 @@ #!/bin/bash # We want to make sure all PRs are targeting the right branch when they're # opened, otherwise we risk (for example) to land a beta-specific change to the -# master branch. This script ensures the branch of the PR matches the channel. +# default branch. This script ensures the branch of the PR matches the channel. set -euo pipefail IFS=$'\n\t' @@ -16,7 +16,7 @@ fi channel=$(cat "$(ciCheckoutPath)/src/ci/channel") case "${channel}" in nightly) - channel_branch="master" + channel_branch="main" ;; beta) channel_branch="beta" diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 51f79047f9914..e6b7a6bfcfb6b 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -166,6 +166,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions remap_path_prefix: options.remap_path_prefix.clone(), unstable_opts: options.unstable_opts.clone(), error_format: options.error_format.clone(), + target_modifiers: options.target_modifiers.clone(), ..config::Options::default() }; diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 6c177f942fb05..e9f5024e494d1 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -8,8 +8,8 @@ use std::sync::Arc; use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind}; -use rustc_errors::emitter::stderr_destination; -use rustc_errors::{AutoStream, ColorConfig, DiagCtxtHandle}; +use rustc_errors::emitter::get_stderr_color_choice; +use rustc_errors::{AutoStream, ColorChoice, ColorConfig, DiagCtxtHandle}; use rustc_parse::lexer::StripTokens; use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; @@ -446,7 +446,7 @@ fn parse_source( span: Span, ) -> Result { use rustc_errors::DiagCtxt; - use rustc_errors::emitter::{Emitter, HumanEmitter}; + use rustc_errors::emitter::HumanEmitter; use rustc_span::source_map::FilePathMapping; let mut info = @@ -458,9 +458,12 @@ fn parse_source( let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let translator = rustc_driver::default_translator(); - info.supports_color = - HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator.clone()) - .supports_color(); + let supports_color = match get_stderr_color_choice(ColorConfig::Auto, &std::io::stderr()) { + ColorChoice::Auto => unreachable!(), + ColorChoice::AlwaysAnsi | ColorChoice::Always => true, + ColorChoice::Never => false, + }; + info.supports_color = supports_color; // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that the parser emits directly into a `Sink` instead of stderr. let emitter = HumanEmitter::new(AutoStream::never(Box::new(io::sink())), translator); diff --git a/src/stage0 b/src/stage0 index 2c12bf4945854..27f9d8d363bfc 100644 --- a/src/stage0 +++ b/src/stage0 @@ -2,7 +2,7 @@ dist_server=https://static.rust-lang.org artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt git_merge_commit_email=bors@rust-lang.org -nightly_branch=master +nightly_branch=main # The configuration above this comment is editable, and can be changed # by forks of the repository if they have alternate values. diff --git a/tests/run-make/rustdoc-target-modifiers/rmake.rs b/tests/run-make/rustdoc-target-modifiers/rmake.rs index ee522501fd286..ffe87f3f7650e 100644 --- a/tests/run-make/rustdoc-target-modifiers/rmake.rs +++ b/tests/run-make/rustdoc-target-modifiers/rmake.rs @@ -25,4 +25,43 @@ fn main() { .target("aarch64-unknown-none-softfloat") .arg("-Zfixed-x18") .run(); + + rustdoc() + .input("c.rs") + .crate_type("rlib") + .extern_("d", "libd.rmeta") + .target("aarch64-unknown-none-softfloat") + .arg("-Zfixed-x18") + .arg("--test") + .run(); + + rustdoc() + .input("c.rs") + .edition("2024") + .crate_type("rlib") + .extern_("d", "libd.rmeta") + .target("aarch64-unknown-none-softfloat") + .arg("-Zfixed-x18") + .arg("--test") + .run(); + + // rustdoc --test detects ABI mismatch + rustdoc() + .input("c.rs") + .crate_type("rlib") + .extern_("d", "libd.rmeta") + .target("aarch64-unknown-none-softfloat") + .arg("--test") + .run_fail() + .assert_stderr_contains("mixing `-Zfixed-x18` will cause an ABI mismatch"); + + // rustdoc --test -Cunsafe-allow-abi-mismatch=... ignores the mismatch + rustdoc() + .input("c.rs") + .crate_type("rlib") + .extern_("d", "libd.rmeta") + .target("aarch64-unknown-none-softfloat") + .arg("--test") + .arg("-Cunsafe-allow-abi-mismatch=fixed-x18") + .run(); } diff --git a/tests/ui/drop/or-pattern-drop-order.rs b/tests/ui/drop/or-pattern-drop-order.rs index 88355a4937e4f..c7913be032eab 100644 --- a/tests/ui/drop/or-pattern-drop-order.rs +++ b/tests/ui/drop/or-pattern-drop-order.rs @@ -33,15 +33,15 @@ fn main() { // Drops are right-to-left: `z`, `y`, `x`. let (x, Ok(y) | Err(y), z); // Assignment order doesn't matter. - z = LogDrop(o, 1); - y = LogDrop(o, 2); - x = LogDrop(o, 3); + z = LogDrop(o, 1); //~ WARN value assigned to `z` is never read + y = LogDrop(o, 2); //~ WARN value assigned to `y` is never read + x = LogDrop(o, 3); //~ WARN value assigned to `x` is never read }); assert_drop_order(1..=2, |o| { // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. let ((true, x, y) | (false, y, x)); - x = LogDrop(o, 2); - y = LogDrop(o, 1); + x = LogDrop(o, 2); //~ WARN value assigned to `x` is never read + y = LogDrop(o, 1); //~ WARN value assigned to `y` is never read }); // `let pat = expr;` should have the same drop order. @@ -61,15 +61,21 @@ fn main() { // `match` should have the same drop order. assert_drop_order(1..=3, |o| { // Drops are right-to-left: `z`, `y` `x`. - match (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)) { (x, Ok(y) | Err(y), z) => {} } + match (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)) { + (x, Ok(y) | Err(y), z) => {} + } }); assert_drop_order(1..=2, |o| { // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. - match (true, LogDrop(o, 2), LogDrop(o, 1)) { (true, x, y) | (false, y, x) => {} } + match (true, LogDrop(o, 2), LogDrop(o, 1)) { + (true, x, y) | (false, y, x) => {} + } }); assert_drop_order(1..=2, |o| { // That drop order is used regardless of which or-pattern alternative matches: `y`, `x`. - match (false, LogDrop(o, 1), LogDrop(o, 2)) { (true, x, y) | (false, y, x) => {} } + match (false, LogDrop(o, 1), LogDrop(o, 2)) { + (true, x, y) | (false, y, x) => {} + } }); // Function params are visited one-by-one, and the order of bindings within a param's pattern is diff --git a/tests/ui/drop/or-pattern-drop-order.stderr b/tests/ui/drop/or-pattern-drop-order.stderr new file mode 100644 index 0000000000000..3d1aa69fb91a8 --- /dev/null +++ b/tests/ui/drop/or-pattern-drop-order.stderr @@ -0,0 +1,43 @@ +warning: value assigned to `x` is never read + --> $DIR/or-pattern-drop-order.rs:43:9 + | +LL | x = LogDrop(o, 2); + | ^ + | + = help: maybe it is overwritten before being read? + = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default + +warning: value assigned to `y` is never read + --> $DIR/or-pattern-drop-order.rs:44:9 + | +LL | y = LogDrop(o, 1); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `x` is never read + --> $DIR/or-pattern-drop-order.rs:38:9 + | +LL | x = LogDrop(o, 3); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `y` is never read + --> $DIR/or-pattern-drop-order.rs:37:9 + | +LL | y = LogDrop(o, 2); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `z` is never read + --> $DIR/or-pattern-drop-order.rs:36:9 + | +LL | z = LogDrop(o, 1); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: 5 warnings emitted + diff --git a/tests/ui/lint/unused/unused-assign-148960.rs b/tests/ui/lint/unused/unused-assign-148960.rs new file mode 100644 index 0000000000000..2e51c01398a37 --- /dev/null +++ b/tests/ui/lint/unused/unused-assign-148960.rs @@ -0,0 +1,42 @@ +//@ check-fail +#![deny(unused)] +#![allow(dead_code)] + +fn test_one_extra_assign() { + let mut value = b"0".to_vec(); //~ ERROR value assigned to `value` is never read + value = b"1".to_vec(); + println!("{:?}", value); +} + +fn test_two_extra_assign() { + let mut x = 1; //~ ERROR value assigned to `x` is never read + x = 2; //~ ERROR value assigned to `x` is never read + x = 3; + println!("{}", x); +} + +struct Point { + x: i32, + y: i32, +} + +fn test_indirect_assign() { + let mut p = Point { x: 1, y: 1 }; //~ ERROR value assigned to `p` is never read + p = Point { x: 2, y: 2 }; + p.x = 3; + println!("{}", p.y); +} + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) {} +} + +// testcase for issue #148418 +fn test_unused_variable() { + let mut foo = Foo; //~ ERROR variable `foo` is assigned to, but never used + foo = Foo; //~ ERROR value assigned to `foo` is never read +} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-assign-148960.stderr b/tests/ui/lint/unused/unused-assign-148960.stderr new file mode 100644 index 0000000000000..0e23fabd5f561 --- /dev/null +++ b/tests/ui/lint/unused/unused-assign-148960.stderr @@ -0,0 +1,62 @@ +error: value assigned to `value` is never read + --> $DIR/unused-assign-148960.rs:6:21 + | +LL | let mut value = b"0".to_vec(); + | ^^^^^^^^^^^^^ + | + = help: maybe it is overwritten before being read? +note: the lint level is defined here + --> $DIR/unused-assign-148960.rs:2:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_assignments)]` implied by `#[deny(unused)]` + +error: value assigned to `x` is never read + --> $DIR/unused-assign-148960.rs:12:17 + | +LL | let mut x = 1; + | ^ + | + = help: maybe it is overwritten before being read? + +error: value assigned to `x` is never read + --> $DIR/unused-assign-148960.rs:13:5 + | +LL | x = 2; + | ^^^^^ + | + = help: maybe it is overwritten before being read? + +error: value assigned to `p` is never read + --> $DIR/unused-assign-148960.rs:24:17 + | +LL | let mut p = Point { x: 1, y: 1 }; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: maybe it is overwritten before being read? + +error: variable `foo` is assigned to, but never used + --> $DIR/unused-assign-148960.rs:38:9 + | +LL | let mut foo = Foo; + | ^^^^^^^ + | + = note: consider using `_foo` instead + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` +help: you might have meant to pattern match on the similarly named struct `Foo` + | +LL - let mut foo = Foo; +LL + let Foo = Foo; + | + +error: value assigned to `foo` is never read + --> $DIR/unused-assign-148960.rs:39:5 + | +LL | foo = Foo; + | ^^^ + | + = help: maybe it is overwritten before being read? + +error: aborting due to 6 previous errors + diff --git a/tests/ui/lint/unused/unused-var-in-unreachable-code.rs b/tests/ui/lint/unused/unused-var-in-unreachable-code.rs new file mode 100644 index 0000000000000..39c5e0315d9ce --- /dev/null +++ b/tests/ui/lint/unused/unused-var-in-unreachable-code.rs @@ -0,0 +1,46 @@ +//@ check-pass + +#![allow(unreachable_code)] +#![allow(dead_code)] +#![warn(unused_variables)] + +fn after_todo() { + todo!("not implemented"); + + // This should not warn - the code is unreachable + let a = 1; + if a < 2 { + eprintln!("a: {}", a); + } +} + +fn after_panic() { + panic!("oops"); + + // This should not warn - the code is unreachable + let b = 2; + println!("{}", b); +} + +fn after_unimplemented() { + unimplemented!(); + + // This should not warn - the code is unreachable + let c = 3; + println!("{}", c); +} + +fn after_unreachable() { + unsafe { std::hint::unreachable_unchecked() } + + // This should not warn - the code is unreachable + let d = 4; + println!("{}", d); +} + +fn reachable_unused() { + // This SHOULD warn - the code is reachable + let e = 5; //~ WARN unused variable: `e` +} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-var-in-unreachable-code.stderr b/tests/ui/lint/unused/unused-var-in-unreachable-code.stderr new file mode 100644 index 0000000000000..dfc2f9c8fc56a --- /dev/null +++ b/tests/ui/lint/unused/unused-var-in-unreachable-code.stderr @@ -0,0 +1,14 @@ +warning: unused variable: `e` + --> $DIR/unused-var-in-unreachable-code.rs:43:9 + | +LL | let e = 5; + | ^ help: if this is intentional, prefix it with an underscore: `_e` + | +note: the lint level is defined here + --> $DIR/unused-var-in-unreachable-code.rs:5:9 + | +LL | #![warn(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs index 639d7c2776dee..a291d2489695f 100644 --- a/tests/ui/liveness/liveness-unused.rs +++ b/tests/ui/liveness/liveness-unused.rs @@ -244,8 +244,8 @@ fn f10(mut a: T, b: T) { //~^ ERROR value assigned to `a` is never read } -fn f10b(mut a: Box, b: Box) { - a = b; +fn f10b(mut a: Box, b: Box) { //~ ERROR variable `a` is assigned to, but never used + a = b; //~ ERROR value assigned to `a` is never read } // unused params warnings are not needed for intrinsic functions without bodies diff --git a/tests/ui/liveness/liveness-unused.stderr b/tests/ui/liveness/liveness-unused.stderr index 23a26841be2fc..f56ca7823e165 100644 --- a/tests/ui/liveness/liveness-unused.stderr +++ b/tests/ui/liveness/liveness-unused.stderr @@ -283,5 +283,21 @@ LL | a = b; | = help: maybe it is overwritten before being read? -error: aborting due to 34 previous errors; 1 warning emitted +error: variable `a` is assigned to, but never used + --> $DIR/liveness-unused.rs:247:12 + | +LL | fn f10b(mut a: Box, b: Box) { + | ^^^^^ + | + = note: consider using `_a` instead + +error: value assigned to `a` is never read + --> $DIR/liveness-unused.rs:248:5 + | +LL | a = b; + | ^ + | + = help: maybe it is overwritten before being read? + +error: aborting due to 36 previous errors; 1 warning emitted diff --git a/tests/ui/return/early-return-with-unreachable-code-24353.rs b/tests/ui/return/early-return-with-unreachable-code-24353.rs index 41d77fea49ac9..13add4652d994 100644 --- a/tests/ui/return/early-return-with-unreachable-code-24353.rs +++ b/tests/ui/return/early-return-with-unreachable-code-24353.rs @@ -4,7 +4,6 @@ fn main() { return (); let x = (); - //~^ WARN unused variable: `x` x } diff --git a/tests/ui/return/early-return-with-unreachable-code-24353.stderr b/tests/ui/return/early-return-with-unreachable-code-24353.stderr deleted file mode 100644 index 92526faef33bb..0000000000000 --- a/tests/ui/return/early-return-with-unreachable-code-24353.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: unused variable: `x` - --> $DIR/early-return-with-unreachable-code-24353.rs:6:9 - | -LL | let x = (); - | ^ help: if this is intentional, prefix it with an underscore: `_x` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default - -warning: 1 warning emitted - diff --git a/tests/ui/suggestions/auxiliary/hidden-struct.rs b/tests/ui/suggestions/auxiliary/hidden-struct.rs index 1f495a9f2224a..ee24389bebd7c 100644 --- a/tests/ui/suggestions/auxiliary/hidden-struct.rs +++ b/tests/ui/suggestions/auxiliary/hidden-struct.rs @@ -33,3 +33,6 @@ impl Marker for hidden::Foo {} impl Marker for hidden1::Bar {} impl Marker for Baz {} impl Marker for Quux {} + + +pub use crate as library; diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs index a83e496f2703d..0716e4e2e143b 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs @@ -21,7 +21,12 @@ pub fn test4(_: Quux) {} fn test5() {} +fn test6() {} + fn main() { test5::(); //~^ ERROR [E0277] + + test6::(); + //~^ ERROR [E0277] } diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr index 7036708756d6c..21ab7441d43c1 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr @@ -38,7 +38,7 @@ LL + use hidden_struct::Quux; | error[E0277]: the trait bound `i32: Marker` is not satisfied - --> $DIR/dont-suggest-foreign-doc-hidden.rs:25:13 + --> $DIR/dont-suggest-foreign-doc-hidden.rs:27:13 | LL | test5::(); | ^^^ the trait `Marker` is not implemented for `i32` @@ -53,7 +53,23 @@ note: required by a bound in `test5` LL | fn test5() {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test5` -error: aborting due to 5 previous errors +error[E0277]: the trait bound `i32: Marker` is not satisfied + --> $DIR/dont-suggest-foreign-doc-hidden.rs:30:13 + | +LL | test6::(); + | ^^^ the trait `Marker` is not implemented for `i32` + | + = help: the following other types implement trait `Marker`: + Baz + Option + Quux +note: required by a bound in `test6` + --> $DIR/dont-suggest-foreign-doc-hidden.rs:24:13 + | +LL | fn test6() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test6` + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0277, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/triagebot.toml b/triagebot.toml index a0d0b1892e4fe..b6edc229f9a29 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1605,7 +1605,7 @@ labels = ["has-merge-commits", "S-waiting-on-author"] format = "rustc" project-name = "Rust" changelog-path = "RELEASES.md" -changelog-branch = "master" +changelog-branch = "main" [shortcut]