Auto merge of #149572 - cuviper:beta-next, r=cuviper
[beta] backports - rustdoc: Use configured target modifiers when collecting doctests rust-lang/rust#148068 - fix(rustdoc): Color doctest errors rust-lang/rust#148834 - Fix the issue of unused assignment from MIR liveness checking rust-lang/rust#149072 - Skip unused variables warning for unreachable code rust-lang/rust#149096 - In `BTreeMap::eq`, do not compare the elements if the sizes are different. rust-lang/rust#149125 - Handle cycles when checking impl candidates for `doc(hidden)` rust-lang/rust#149185 - Generalize branch references rust-lang/rust#148395 - only the commit updating CI scripts - Change default branch references rust-lang/rust#148564 r? cuviper
This commit is contained in:
commit
ac0aff2115
32 changed files with 506 additions and 75 deletions
2
.github/workflows/post-merge.yml
vendored
2
.github/workflows/post-merge.yml
vendored
|
|
@ -6,7 +6,7 @@ name: Post merge analysis
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<PlaceIndex>| {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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<DefId> = 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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -2414,7 +2414,7 @@ impl<K, V> Default for BTreeMap<K, V> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: PartialEq, V: PartialEq, A: Allocator + Clone> PartialEq for BTreeMap<K, V, A> {
|
||||
fn eq(&self, other: &BTreeMap<K, V, A>) -> bool {
|
||||
self.iter().eq(other)
|
||||
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
96
library/alloctests/tests/collections/eq_diff_len.rs
Normal file
96
library/alloctests/tests/collections/eq_diff_len.rs
Normal file
|
|
@ -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<Ordering> {
|
||||
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);
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
mod binary_heap;
|
||||
mod eq_diff_len;
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
|
|||
/// 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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
"#);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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: <SHA of a commit already in master>\`'
|
||||
echo '\`backport-of: <SHA of a commit already in the default branch>\`'
|
||||
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: <SHA>\`, 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 = <sha>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ParseSourceInfo, ()> {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
43
tests/ui/drop/or-pattern-drop-order.stderr
Normal file
43
tests/ui/drop/or-pattern-drop-order.stderr
Normal file
|
|
@ -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
|
||||
|
||||
42
tests/ui/lint/unused/unused-assign-148960.rs
Normal file
42
tests/ui/lint/unused/unused-assign-148960.rs
Normal file
|
|
@ -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() {}
|
||||
62
tests/ui/lint/unused/unused-assign-148960.stderr
Normal file
62
tests/ui/lint/unused/unused-assign-148960.stderr
Normal file
|
|
@ -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
|
||||
|
||||
46
tests/ui/lint/unused/unused-var-in-unreachable-code.rs
Normal file
46
tests/ui/lint/unused/unused-var-in-unreachable-code.rs
Normal file
|
|
@ -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() {}
|
||||
14
tests/ui/lint/unused/unused-var-in-unreachable-code.stderr
Normal file
14
tests/ui/lint/unused/unused-var-in-unreachable-code.stderr
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -244,8 +244,8 @@ fn f10<T>(mut a: T, b: T) {
|
|||
//~^ ERROR value assigned to `a` is never read
|
||||
}
|
||||
|
||||
fn f10b<T>(mut a: Box<T>, b: Box<T>) {
|
||||
a = b;
|
||||
fn f10b<T>(mut a: Box<T>, b: Box<T>) { //~ 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
|
||||
|
|
|
|||
|
|
@ -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<T>(mut a: Box<T>, b: Box<T>) {
|
||||
| ^^^^^
|
||||
|
|
||||
= 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
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ fn main() {
|
|||
return ();
|
||||
|
||||
let x = ();
|
||||
//~^ WARN unused variable: `x`
|
||||
x
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ pub fn test4(_: Quux) {}
|
|||
|
||||
fn test5<T: hidden_struct::Marker>() {}
|
||||
|
||||
fn test6<T: hidden_struct::library::Marker>() {}
|
||||
|
||||
fn main() {
|
||||
test5::<i32>();
|
||||
//~^ ERROR [E0277]
|
||||
|
||||
test6::<i32>();
|
||||
//~^ ERROR [E0277]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::<i32>();
|
||||
| ^^^ the trait `Marker` is not implemented for `i32`
|
||||
|
|
@ -53,7 +53,23 @@ note: required by a bound in `test5`
|
|||
LL | fn test5<T: hidden_struct::Marker>() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ 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::<i32>();
|
||||
| ^^^ the trait `Marker` is not implemented for `i32`
|
||||
|
|
||||
= help: the following other types implement trait `Marker`:
|
||||
Baz
|
||||
Option<u32>
|
||||
Quux
|
||||
note: required by a bound in `test6`
|
||||
--> $DIR/dont-suggest-foreign-doc-hidden.rs:24:13
|
||||
|
|
||||
LL | fn test6<T: hidden_struct::library::Marker>() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue