1
Fork 0

Auto merge of #139595 - matthiaskrgr:rollup-kaa8aim, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #138470 (Test interaction between RFC 2229 migration and use closures)
 - #138628 (Add more ergonomic clone tests)
 - #139164 (std: improve documentation for get_mut() methods regarding forgotten guards)
 - #139488 (Add missing regression GUI test)
 - #139489 (compiletest: Add directive `dont-require-annotations`)
 - #139513 (Report higher-ranked trait error when higher-ranked projection goal fails in new solver)
 - #139521 (triagebot: roll compiler reviewers for rustc/unstable book)
 - #139532 (Update `u8`-to-and-from-`i8` suggestions.)
 - #139551 (report call site of inlined scopes for large assignment lints)
 - #139575 (Remove redundant words)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-09 21:35:22 +00:00
commit 51548ce71f
36 changed files with 493 additions and 86 deletions

View file

@ -1829,7 +1829,7 @@ pub struct PointeeInfo {
pub safe: Option<PointerKind>, pub safe: Option<PointerKind>,
/// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes. /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
/// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
/// of this function call", i.e. it is UB for the memory that this pointer points to to be freed /// of this function call", i.e. it is UB for the memory that this pointer points to be freed
/// while this function is still running. /// while this function is still running.
/// The size can be zero if the pointer is not dereferenceable. /// The size can be zero if the pointer is not dereferenceable.
pub size: Size, pub size: Size,

View file

@ -148,11 +148,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
span: Span, span: Span,
) { ) {
let source_info = self.body.source_info(location); let source_info = self.body.source_info(location);
for reported_span in &self.move_size_spans {
if reported_span.overlaps(span) {
return;
}
}
let lint_root = source_info.scope.lint_root(&self.body.source_scopes); let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
let Some(lint_root) = lint_root else { let Some(lint_root) = lint_root else {
// This happens when the issue is in a function from a foreign crate that // This happens when the issue is in a function from a foreign crate that
@ -162,13 +158,34 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
// but correct span? This would make the lint at least accept crate-level lint attributes. // but correct span? This would make the lint at least accept crate-level lint attributes.
return; return;
}; };
// If the source scope is inlined by the MIR inliner, report the lint on the call site.
let reported_span = self
.body
.source_scopes
.get(source_info.scope)
.and_then(|source_scope_data| source_scope_data.inlined)
.map(|(_, call_site)| call_site)
.unwrap_or(span);
for previously_reported_span in &self.move_size_spans {
if previously_reported_span.overlaps(reported_span) {
return;
}
}
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
LARGE_ASSIGNMENTS, LARGE_ASSIGNMENTS,
lint_root, lint_root,
span, reported_span,
LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, LargeAssignmentsLint {
span: reported_span,
size: too_large_size.bytes(),
limit: limit as u64,
},
); );
self.move_size_spans.push(span);
self.move_size_spans.push(reported_span);
} }
} }

View file

@ -291,6 +291,34 @@ impl<'tcx> BestObligation<'tcx> {
} }
} }
/// When a higher-ranked projection goal fails, check that the corresponding
/// higher-ranked trait goal holds or not. This is because the process of
/// instantiating and then re-canonicalizing the binder of the projection goal
/// forces us to be unable to see that the leak check failed in the nested
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
/// that should catch when a projection goal fails due to an unsatisfied trait
/// goal.
fn detect_error_in_higher_ranked_projection(
&mut self,
goal: &inspect::InspectGoal<'_, 'tcx>,
) -> ControlFlow<PredicateObligation<'tcx>> {
let tcx = goal.infcx().tcx;
if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
&& !projection_clause.bound_vars().is_empty()
{
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
goal.infcx().visit_proof_tree_at_depth(
goal.goal().with(tcx, pred),
goal.depth() + 1,
this,
)
})
} else {
ControlFlow::Continue(())
}
}
/// It is likely that `NormalizesTo` failed without any applicable candidates /// It is likely that `NormalizesTo` failed without any applicable candidates
/// because the alias is not well-formed. /// because the alias is not well-formed.
/// ///
@ -374,7 +402,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
source: CandidateSource::Impl(impl_def_id), source: CandidateSource::Impl(impl_def_id),
result: _, result: _,
} = candidate.kind() } = candidate.kind()
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id) && tcx.do_not_recommend_impl(impl_def_id)
{ {
trace!("#[do_not_recommend] -> exit"); trace!("#[do_not_recommend] -> exit");
return ControlFlow::Break(self.obligation.clone()); return ControlFlow::Break(self.obligation.clone());
@ -486,7 +514,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
if let Some(obligation) = goal if let Some(obligation) = goal
.infcx() .infcx()
.visit_proof_tree_at_depth( .visit_proof_tree_at_depth(
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
goal.depth() + 1, goal.depth() + 1,
self, self,
) )
@ -496,7 +524,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} else if let Some(obligation) = goal } else if let Some(obligation) = goal
.infcx() .infcx()
.visit_proof_tree_at_depth( .visit_proof_tree_at_depth(
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
goal.depth() + 1, goal.depth() + 1,
self, self,
) )
@ -506,6 +534,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} }
} }
self.detect_error_in_higher_ranked_projection(goal)?;
ControlFlow::Break(self.obligation.clone()) ControlFlow::Break(self.obligation.clone())
} }
} }

View file

@ -1156,7 +1156,9 @@ impl<T: ?Sized> RefCell<T> {
/// Since this method borrows `RefCell` mutably, it is statically guaranteed /// Since this method borrows `RefCell` mutably, it is statically guaranteed
/// that no borrows to the underlying data exist. The dynamic checks inherent /// that no borrows to the underlying data exist. The dynamic checks inherent
/// in [`borrow_mut`] and most other methods of `RefCell` are therefore /// in [`borrow_mut`] and most other methods of `RefCell` are therefore
/// unnecessary. /// unnecessary. Note that this method does not reset the borrowing state if borrows were previously leaked
/// (e.g., via [`forget()`] on a [`Ref`] or [`RefMut`]). For that purpose,
/// consider using the unstable [`undo_leak`] method.
/// ///
/// This method can only be called if `RefCell` can be mutably borrowed, /// This method can only be called if `RefCell` can be mutably borrowed,
/// which in general is only the case directly after the `RefCell` has /// which in general is only the case directly after the `RefCell` has
@ -1167,6 +1169,8 @@ impl<T: ?Sized> RefCell<T> {
/// Use [`borrow_mut`] to get mutable access to the underlying data then. /// Use [`borrow_mut`] to get mutable access to the underlying data then.
/// ///
/// [`borrow_mut`]: RefCell::borrow_mut() /// [`borrow_mut`]: RefCell::borrow_mut()
/// [`forget()`]: mem::forget
/// [`undo_leak`]: RefCell::undo_leak()
/// ///
/// # Examples /// # Examples
/// ///

View file

@ -427,7 +427,7 @@ pub unsafe trait CloneToUninit {
/// read or dropped, because even if it was previously valid, it may have been partially /// read or dropped, because even if it was previously valid, it may have been partially
/// overwritten. /// overwritten.
/// ///
/// The caller may wish to to take care to deallocate the allocation pointed to by `dest`, /// The caller may wish to take care to deallocate the allocation pointed to by `dest`,
/// if applicable, to avoid a memory leak (but this is not a requirement). /// if applicable, to avoid a memory leak (but this is not a requirement).
/// ///
/// Implementors should avoid leaking values by, upon unwinding, dropping all component values /// Implementors should avoid leaking values by, upon unwinding, dropping all component values

View file

@ -99,8 +99,8 @@ macro_rules! i8_xe_bytes_doc {
**Note**: This function is meaningless on `i8`. Byte order does not exist as a **Note**: This function is meaningless on `i8`. Byte order does not exist as a
concept for byte-sized integers. This function is only provided in symmetry concept for byte-sized integers. This function is only provided in symmetry
with larger integer types. You can cast from and to `u8` using `as i8` and `as with larger integer types. You can cast from and to `u8` using
u8`. [`cast_signed`](u8::cast_signed) and [`cast_unsigned`](Self::cast_unsigned).
" "
}; };

View file

@ -582,7 +582,9 @@ impl<T: ?Sized> Mutex<T> {
/// Returns a mutable reference to the underlying data. /// Returns a mutable reference to the underlying data.
/// ///
/// Since this call borrows the `Mutex` mutably, no actual locking needs to /// Since this call borrows the `Mutex` mutably, no actual locking needs to
/// take place -- the mutable borrow statically guarantees no locks exist. /// take place -- the mutable borrow statically guarantees no new locks can be acquired
/// while this reference exists. Note that this method does not clear any previous abandoned locks
/// (e.g., via [`forget()`] on a [`MutexGuard`]).
/// ///
/// # Errors /// # Errors
/// ///
@ -599,6 +601,8 @@ impl<T: ?Sized> Mutex<T> {
/// *mutex.get_mut().unwrap() = 10; /// *mutex.get_mut().unwrap() = 10;
/// assert_eq!(*mutex.lock().unwrap(), 10); /// assert_eq!(*mutex.lock().unwrap(), 10);
/// ``` /// ```
///
/// [`forget()`]: mem::forget
#[stable(feature = "mutex_get_mut", since = "1.6.0")] #[stable(feature = "mutex_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> { pub fn get_mut(&mut self) -> LockResult<&mut T> {
let data = self.data.get_mut(); let data = self.data.get_mut();

View file

@ -608,7 +608,9 @@ impl<T: ?Sized> RwLock<T> {
/// Returns a mutable reference to the underlying data. /// Returns a mutable reference to the underlying data.
/// ///
/// Since this call borrows the `RwLock` mutably, no actual locking needs to /// Since this call borrows the `RwLock` mutably, no actual locking needs to
/// take place -- the mutable borrow statically guarantees no locks exist. /// take place -- the mutable borrow statically guarantees no new locks can be acquired
/// while this reference exists. Note that this method does not clear any previously abandoned locks
/// (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]).
/// ///
/// # Errors /// # Errors
/// ///

View file

@ -33,7 +33,7 @@ For opaque types in the defining scope and in the implicit-negative coherence mo
always done in two steps. Outside of the defining scope `normalizes-to` for opaques always always done in two steps. Outside of the defining scope `normalizes-to` for opaques always
returns `Err(NoSolution)`. returns `Err(NoSolution)`.
We start by trying to to assign the expected type as a hidden type. We start by trying to assign the expected type as a hidden type.
In the implicit-negative coherence mode, this currently always results in ambiguity without In the implicit-negative coherence mode, this currently always results in ambiguity without
interacting with the opaque types storage. We could instead add allow 'defining' all opaque types, interacting with the opaque types storage. We could instead add allow 'defining' all opaque types,

View file

@ -1447,7 +1447,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
cursor: pointer; cursor: pointer;
} }
.setting-check input { .setting-check input {
flex-shrink: 0, flex-shrink: 0;
} }
.setting-radio input:checked { .setting-radio input:checked {

View file

@ -22,6 +22,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"dont-check-compiler-stderr", "dont-check-compiler-stderr",
"dont-check-compiler-stdout", "dont-check-compiler-stdout",
"dont-check-failure-status", "dont-check-failure-status",
"dont-require-annotations",
"edition", "edition",
"error-pattern", "error-pattern",
"exact-llvm-major-version", "exact-llvm-major-version",

View file

@ -8,7 +8,7 @@ use std::sync::OnceLock;
use regex::Regex; use regex::Regex;
use tracing::*; use tracing::*;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ErrorKind { pub enum ErrorKind {
Help, Help,
Error, Error,
@ -40,6 +40,15 @@ impl ErrorKind {
_ => return None, _ => return None,
}) })
} }
pub fn expect_from_user_str(s: &str) -> ErrorKind {
ErrorKind::from_user_str(s).unwrap_or_else(|| {
panic!(
"unexpected diagnostic kind `{s}`, expected \
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
)
})
}
} }
impl fmt::Display for ErrorKind { impl fmt::Display for ErrorKind {

View file

@ -1,4 +1,4 @@
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
@ -11,6 +11,7 @@ use tracing::*;
use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
use crate::debuggers::{extract_cdb_version, extract_gdb_version}; use crate::debuggers::{extract_cdb_version, extract_gdb_version};
use crate::errors::ErrorKind;
use crate::executor::{CollectedTestDesc, ShouldPanic}; use crate::executor::{CollectedTestDesc, ShouldPanic};
use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
use crate::header::needs::CachedNeedsConditions; use crate::header::needs::CachedNeedsConditions;
@ -196,6 +197,8 @@ pub struct TestProps {
/// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios
/// that don't otherwise want/need `-Z build-std`. /// that don't otherwise want/need `-Z build-std`.
pub add_core_stubs: bool, pub add_core_stubs: bool,
/// Whether line annotatins are required for the given error kind.
pub require_annotations: HashMap<ErrorKind, bool>,
} }
mod directives { mod directives {
@ -212,6 +215,7 @@ mod directives {
pub const CHECK_RUN_RESULTS: &'static str = "check-run-results"; pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout"; pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout";
pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr"; pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr";
pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations";
pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic"; pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic";
pub const PRETTY_MODE: &'static str = "pretty-mode"; pub const PRETTY_MODE: &'static str = "pretty-mode";
pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only"; pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only";
@ -297,6 +301,13 @@ impl TestProps {
no_auto_check_cfg: false, no_auto_check_cfg: false,
has_enzyme: false, has_enzyme: false,
add_core_stubs: false, add_core_stubs: false,
require_annotations: HashMap::from([
(ErrorKind::Help, true),
(ErrorKind::Note, true),
(ErrorKind::Error, true),
(ErrorKind::Warning, true),
(ErrorKind::Suggestion, false),
]),
} }
} }
@ -570,6 +581,13 @@ impl TestProps {
config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg); config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);
self.update_add_core_stubs(ln, config); self.update_add_core_stubs(ln, config);
if let Some(err_kind) =
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
{
self.require_annotations
.insert(ErrorKind::expect_from_user_str(&err_kind), false);
}
}, },
); );

View file

@ -709,10 +709,6 @@ impl<'test> TestCx<'test> {
self.testpaths.file.display().to_string() self.testpaths.file.display().to_string()
}; };
// If the testcase being checked contains at least one expected "help"
// message, then we'll ensure that all "help" messages are expected.
// Otherwise, all "help" messages reported by the compiler will be ignored.
// This logic also applies to "note" messages.
let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
@ -800,9 +796,7 @@ impl<'test> TestCx<'test> {
} }
/// Returns `true` if we should report an error about `actual_error`, /// Returns `true` if we should report an error about `actual_error`,
/// which did not match any of the expected error. We always require /// which did not match any of the expected error.
/// errors/warnings to be explicitly listed, but only require
/// helps/notes if there are explicit helps/notes given.
fn is_unexpected_compiler_message( fn is_unexpected_compiler_message(
&self, &self,
actual_error: &Error, actual_error: &Error,
@ -810,12 +804,16 @@ impl<'test> TestCx<'test> {
expect_note: bool, expect_note: bool,
) -> bool { ) -> bool {
actual_error.require_annotation actual_error.require_annotation
&& match actual_error.kind { && actual_error.kind.map_or(false, |err_kind| {
Some(ErrorKind::Help) => expect_help, // If the test being checked doesn't contain any "help" or "note" annotations, then
Some(ErrorKind::Note) => expect_note, // we don't require annotating "help" or "note" (respecively) diagnostics at all.
Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true, let default_require_annotations = self.props.require_annotations[&err_kind];
Some(ErrorKind::Suggestion) | None => false, match err_kind {
} ErrorKind::Help => expect_help && default_require_annotations,
ErrorKind::Note => expect_note && default_require_annotations,
_ => default_require_annotations,
}
})
} }
fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit { fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {

View file

@ -314,6 +314,13 @@ compare-elements-position: (".sub form", "#settings", ["x"])
// Check that setting-line has the same margin in this mode as in the popover. // Check that setting-line has the same margin in this mode as in the popover.
assert-css: (".setting-line", {"margin": |setting_line_margin|}) assert-css: (".setting-line", {"margin": |setting_line_margin|})
// We will check that the checkboxes size doesn't change either.
assert-size: (
"#settings label > input[type='checkbox']",
{"width": 19, "height": 19},
ALL,
)
// We now check the display with JS disabled. // We now check the display with JS disabled.
assert-false: "noscript section" assert-false: "noscript section"
javascript: false javascript: false
@ -327,3 +334,10 @@ reload:
set-window-size: (300, 1000) set-window-size: (300, 1000)
wait-for: "#settings" wait-for: "#settings"
assert-css: (".setting-radio", {"cursor": "pointer"}) assert-css: (".setting-radio", {"cursor": "pointer"})
// We ensure that the checkboxes size didn't change.
assert-size: (
"#settings label > input[type='checkbox']",
{"width": 19, "height": 19},
ALL,
)

View file

@ -1,7 +1,6 @@
// Error, the linked empty library is `no_std` and doesn't provide a panic handler. // Error, the linked empty library is `no_std` and doesn't provide a panic handler.
//@ compile-flags: --error-format=human //@ dont-require-annotations:ERROR
//@ error-pattern: `#[panic_handler]` function required, but not found
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build: cfg_false_lib_no_std_before.rs //@ aux-build: cfg_false_lib_no_std_before.rs
@ -11,6 +10,7 @@ extern crate cfg_false_lib_no_std_before as _;
fn main() {} fn main() {}
// FIXME: The second error is target-dependent. //~? ERROR `#[panic_handler]` function required, but not found
//FIXME~? ERROR `#[panic_handler]` function required, but not found // FIXME: This error is target-dependent, could be served by some "optional error" annotation
// instead of `dont-require-annotations`.
//FIXME~? ERROR unwinding panics are not supported without std //FIXME~? ERROR unwinding panics are not supported without std

View file

@ -0,0 +1,35 @@
#![feature(ergonomic_clones)]
#![allow(incomplete_features)]
use std::clone::UseCloned;
fn takes_val<T>(_: T) {}
fn takes_ref<'a, T>(_: &'a T) {}
#[derive(Clone)]
struct Inner<'a, T>(&'a T);
impl<'a, T> UseCloned for Inner<'a, T> where T: Clone {}
fn main() {
let v = String::new();
let inner = Inner(&v);
let _ = use || {
takes_ref(inner.0);
takes_val(inner.0)
};
let _ = use || {
takes_ref(inner.0);
takes_val(inner.0);
takes_val(inner.0);
takes_val(inner)
};
let _ = use || {
takes_ref(inner.0);
takes_val(inner.0);
takes_val(inner);
takes_val(inner)
//~^ ERROR: use of moved value: `inner` [E0382]
};
}

View file

@ -0,0 +1,13 @@
error[E0382]: use of moved value: `inner`
--> $DIR/multiple-use-variants.rs:32:19
|
LL | takes_val(inner);
| ----- value moved here
LL | takes_val(inner)
| ^^^^^ value used here after move
|
= note: move occurs because `inner` has type `Inner<'_, String>`, which does not implement the `Copy` trait
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,26 @@
//@ run-rustfix
//@ edition:2018
//@ check-pass
#![feature(ergonomic_clones)]
#![warn(rust_2021_compatibility)]
#![allow(incomplete_features)]
#[derive(Debug)]
struct Foo(i32);
impl Drop for Foo {
fn drop(&mut self) {
println!("{:?} dropped", self.0);
}
}
fn main() {
let a = (Foo(0), Foo(1));
let f = use || {
let _ = &a;
//~^ HELP: add a dummy
//~| WARNING: drop order
let x = a.0;
println!("{:?}", x);
};
f();
}

View file

@ -0,0 +1,25 @@
//@ run-rustfix
//@ edition:2018
//@ check-pass
#![feature(ergonomic_clones)]
#![warn(rust_2021_compatibility)]
#![allow(incomplete_features)]
#[derive(Debug)]
struct Foo(i32);
impl Drop for Foo {
fn drop(&mut self) {
println!("{:?} dropped", self.0);
}
}
fn main() {
let a = (Foo(0), Foo(1));
let f = use || {
//~^ HELP: add a dummy
//~| WARNING: drop order
let x = a.0;
println!("{:?}", x);
};
f();
}

View file

@ -0,0 +1,27 @@
warning: changes to closure capture in Rust 2021 will affect drop order
--> $DIR/rfc2229-migration.rs:18:13
|
LL | let f = use || {
| ^^^^^^
...
LL | let x = a.0;
| --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
...
LL | }
| - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
note: the lint level is defined here
--> $DIR/rfc2229-migration.rs:5:9
|
LL | #![warn(rust_2021_compatibility)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]`
help: add a dummy let to cause `a` to be fully captured
|
LL ~ let f = use || {
LL + let _ = &a;
|
warning: 1 warning emitted

View file

@ -0,0 +1,28 @@
error[E0382]: use of moved value: `x`
--> $DIR/spawn-thread.rs:15:42
|
LL | let x = (Arc::new("foo".to_owned()), Arc::new(vec![1, 2, 3]), Arc::new(1));
| - move occurs because `x` has type `(Arc<String>, Arc<Vec<i32>>, Arc<i32>)`, which does not implement the `Copy` trait
LL | for _ in 0..10 {
| -------------- inside of this loop
LL | let handler = std::thread::spawn(use || {
| __________________________________________-^^^^^
LL | |
LL | | drop((x.0, x.1, x.2));
| | --- use occurs due to use in closure
LL | | });
| |_________- value moved here, in previous iteration of loop
|
help: consider moving the expression out of the loop so it is only moved once
|
LL ~ let mut value = std::thread::spawn(use || {
LL +
LL + drop((x.0, x.1, x.2));
LL + });
LL ~ for _ in 0..10 {
LL ~ let handler = value;
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,50 @@
//@ revisions: edition2018 edition2024
//@ [edition2018] edition: 2018
//@ [edition2024] edition: 2024
//@ [edition2024] check-pass
#![feature(ergonomic_clones)]
#![allow(incomplete_features)]
use std::sync::Arc;
fn foo() {
// The type is a tuple and doesn't implement UseCloned
let x = (Arc::new("foo".to_owned()), Arc::new(vec![1, 2, 3]), Arc::new(1));
for _ in 0..10 {
let handler = std::thread::spawn(use || {
//[edition2018]~^ ERROR use of moved value: `x` [E0382]
drop((x.0, x.1, x.2));
});
handler.join().unwrap();
}
}
fn bar() {
let x = Arc::new("foo".to_owned());
let y = Arc::new(vec![1, 2, 3]);
let z = Arc::new(1);
for _ in 0..10 {
let handler = std::thread::spawn(use || {
drop((x, y, z));
});
handler.join().unwrap();
}
}
fn baz() {
use std::sync::Arc;
use std::thread;
let five = Arc::new(5);
for _ in 0..10 {
let handler = thread::spawn(use || {
println!("{five:?}");
});
handler.join().unwrap();
}
}
fn main() {}

View file

@ -0,0 +1,11 @@
//@ check-pass
#![feature(ergonomic_clones)]
#![allow(incomplete_features)]
fn use_block_test(x: i32) -> i32 {
let x = { let x = x + 1; x }.use;
x
}
fn main() {}

View file

@ -13,7 +13,7 @@ LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@ -22,7 +22,7 @@ LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
found associated type `<T as Trait<'a>>::Assoc` found associated type `<T as Trait<'a>>::Assoc`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other

View file

@ -22,38 +22,20 @@ note: required by a bound in `projection_bound`
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {} LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
--> $DIR/candidate-from-env-universe-err-project.rs:38:24
|
LL | projection_bound::<T>();
| ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
|
note: types differ
--> $DIR/candidate-from-env-universe-err-project.rs:14:18
|
LL | type Assoc = usize;
| ^^^^^
note: required by a bound in `projection_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
error: higher-ranked subtype error error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 5 previous errors error: aborting due to 4 previous errors
Some errors have detailed explanations: E0271, E0277. For more information about this error, try `rustc --explain E0277`.
For more information about an error, try `rustc --explain E0271`.

View file

@ -36,9 +36,8 @@ fn function2<T: Trait<'static, Assoc = usize>>() {
// does not use the leak check when trying the where-bound, causing us // does not use the leak check when trying the where-bound, causing us
// to prefer it over the impl, resulting in a placeholder error. // to prefer it over the impl, resulting in a placeholder error.
projection_bound::<T>(); projection_bound::<T>();
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize` //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
//[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied //[current]~^^ ERROR mismatched types
//[current]~^^^ ERROR mismatched types
} }
fn function3<T: Trait<'static, Assoc = usize>>() { fn function3<T: Trait<'static, Assoc = usize>>() {

View file

@ -0,0 +1,24 @@
#![feature(large_assignments)]
#![deny(large_assignments)]
#![move_size_limit = "1000"]
//! Tests that with `-Zinline-mir`, we do NOT get an error that points to the
//! implementation of `UnsafeCell` since that is not actionable by the user:
//!
//! ```text
//! error: moving 9999 bytes
//! --> /rustc/FAKE_PREFIX/library/core/src/cell.rs:2054:9
//! |
//! = note: value moved from here
//! ```
//!
//! We want the diagnostics to point to the relevant user code.
//@ build-fail
//@ compile-flags: -Zmir-opt-level=1 -Zinline-mir
pub fn main() {
let data = [10u8; 9999];
let cell = std::cell::UnsafeCell::new(data); //~ ERROR large_assignments
std::hint::black_box(cell);
}

View file

@ -0,0 +1,15 @@
error: moving 9999 bytes
--> $DIR/inline_mir.rs:22:16
|
LL | let cell = std::cell::UnsafeCell::new(data);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here
|
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
note: the lint level is defined here
--> $DIR/inline_mir.rs:2:9
|
LL | #![deny(large_assignments)]
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,5 +1,5 @@
error: implementation of `FnOnce` is not general enough error: implementation of `FnOnce` is not general enough
--> $DIR/closure-mismatch.rs:8:5 --> $DIR/closure-mismatch.rs:12:5
| |
LL | baz(|_| ()); LL | baz(|_| ());
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@ -8,7 +8,7 @@ LL | baz(|_| ());
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `Fn` is not general enough error: implementation of `Fn` is not general enough
--> $DIR/closure-mismatch.rs:8:5 --> $DIR/closure-mismatch.rs:12:5
| |
LL | baz(|_| ()); LL | baz(|_| ());
| ^^^^^^^^^^^ implementation of `Fn` is not general enough | ^^^^^^^^^^^ implementation of `Fn` is not general enough
@ -17,7 +17,7 @@ LL | baz(|_| ());
= note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough error: implementation of `FnOnce` is not general enough
--> $DIR/closure-mismatch.rs:11:5 --> $DIR/closure-mismatch.rs:16:5
| |
LL | baz(|x| ()); LL | baz(|x| ());
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@ -26,7 +26,7 @@ LL | baz(|x| ());
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `Fn` is not general enough error: implementation of `Fn` is not general enough
--> $DIR/closure-mismatch.rs:11:5 --> $DIR/closure-mismatch.rs:16:5
| |
LL | baz(|x| ()); LL | baz(|x| ());
| ^^^^^^^^^^^ implementation of `Fn` is not general enough | ^^^^^^^^^^^ implementation of `Fn` is not general enough

View file

@ -0,0 +1,67 @@
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}: Foo` is not satisfied
--> $DIR/closure-mismatch.rs:12:9
|
LL | baz(|_| ());
| --- ^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}`
= note: expected a closure with signature `for<'a> fn(&'a ())`
found a closure with signature `fn(&())`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/closure-mismatch.rs:12:9
|
LL | baz(|_| ());
| ----^^^----
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required for `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` to implement `Foo`
--> $DIR/closure-mismatch.rs:7:18
|
LL | impl<T: Fn(&())> Foo for T {}
| ------- ^^^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `baz`
--> $DIR/closure-mismatch.rs:9:11
|
LL | fn baz<T: Foo>(_: T) {}
| ^^^ required by this bound in `baz`
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}: Foo` is not satisfied
--> $DIR/closure-mismatch.rs:16:9
|
LL | baz(|x| ());
| --- ^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}`
= note: expected a closure with signature `for<'a> fn(&'a ())`
found a closure with signature `fn(&())`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/closure-mismatch.rs:16:9
|
LL | baz(|x| ());
| ----^^^----
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required for `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` to implement `Foo`
--> $DIR/closure-mismatch.rs:7:18
|
LL | impl<T: Fn(&())> Foo for T {}
| ------- ^^^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `baz`
--> $DIR/closure-mismatch.rs:9:11
|
LL | fn baz<T: Foo>(_: T) {}
| ^^^ required by this bound in `baz`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,3 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
trait Foo {} trait Foo {}
impl<T: Fn(&())> Foo for T {} impl<T: Fn(&())> Foo for T {}
@ -6,9 +10,11 @@ fn baz<T: Foo>(_: T) {}
fn main() { fn main() {
baz(|_| ()); baz(|_| ());
//~^ ERROR implementation of `FnOnce` is not general enough //[current]~^ ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `Fn` is not general enough //[current]~| ERROR implementation of `Fn` is not general enough
//[next]~^^^ ERROR Foo` is not satisfied
baz(|x| ()); baz(|x| ());
//~^ ERROR implementation of `FnOnce` is not general enough //[current]~^ ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `Fn` is not general enough //[current]~| ERROR implementation of `Fn` is not general enough
//[next]~^^^ ERROR Foo` is not satisfied
} }

View file

@ -1,7 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ compile-flags: --error-format=human //@ dont-require-annotations:ERROR
//@ error-pattern: cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ aux-build:panic-runtime-unwind2.rs //@ aux-build:panic-runtime-unwind2.rs
@ -16,7 +15,8 @@ extern crate panic_runtime_lang_items;
fn main() {} fn main() {}
// FIXME: The second and third errors are target-dependent. //~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
//FIXME~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 // FIXME: These errors are target-dependent, could be served by some "optional error" annotation
// instead of `dont-require-annotations`.
//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind2` is not compiled with this crate's panic strategy `abort` //FIXME~? ERROR the linked panic runtime `panic_runtime_unwind2` is not compiled with this crate's panic strategy `abort`
//FIXME~? ERROR the crate `panic_runtime_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` //FIXME~? ERROR the crate `panic_runtime_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`

View file

@ -1,7 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ compile-flags: --error-format=human //@ dont-require-annotations:ERROR
//@ error-pattern: the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ compile-flags:-C panic=abort //@ compile-flags:-C panic=abort
@ -10,7 +9,8 @@ extern crate panic_runtime_unwind;
fn main() {} fn main() {}
// FIXME: The first and third errors are target-dependent. //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
// FIXME: These errors are target-dependent, could be served by some "optional error" annotation
// instead of `dont-require-annotations`.
//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind //FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind
//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` //FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`

View file

@ -1,7 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ compile-flags: --error-format=human //@ dont-require-annotations:ERROR
//@ error-pattern: the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ aux-build:wants-panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs
@ -11,7 +10,8 @@ extern crate wants_panic_runtime_unwind;
fn main() {} fn main() {}
// FIXME: The first and third errors are target-dependent. //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
// FIXME: These errors are target-dependent, could be served by some "optional error" annotation
// instead of `dont-require-annotations`.
//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind //FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind
//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort`
//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` //FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`

View file

@ -1338,9 +1338,11 @@ compiletest = [
"/src/doc/nomicon" = ["@ehuss"] "/src/doc/nomicon" = ["@ehuss"]
"/src/doc/reference" = ["@ehuss"] "/src/doc/reference" = ["@ehuss"]
"/src/doc/rust-by-example" = ["@ehuss"] "/src/doc/rust-by-example" = ["@ehuss"]
"/src/doc/rustc" = ["compiler", "@ehuss"]
"/src/doc/rustc-dev-guide" = ["compiler"] "/src/doc/rustc-dev-guide" = ["compiler"]
"/src/doc/rustdoc" = ["rustdoc"] "/src/doc/rustdoc" = ["rustdoc"]
"/src/doc/style-guide" = ["style-team"] "/src/doc/style-guide" = ["style-team"]
"/src/doc/unstable-book" = ["compiler"]
"/src/etc" = ["@Mark-Simulacrum"] "/src/etc" = ["@Mark-Simulacrum"]
"/src/librustdoc" = ["rustdoc"] "/src/librustdoc" = ["rustdoc"]
"/src/llvm-project" = ["@cuviper"] "/src/llvm-project" = ["@cuviper"]