mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
Auto merge of #94634 - Dylan-DPC:rollup-8wx1yrj, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #94446 (UNIX `remove_dir_all()`: Try recursing first on the slow path) - #94460 (Reenable generator drop tracking tests and fix mutation handling) - #94620 (Edit docs on consistency of `PartialOrd` and `PartialEq`) - #94624 (Downgrade `#[test]` on macro call to warning) - #94626 (Add known-bug directive to issue #47511 test case) - #94631 (Fix typo in c-variadic) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
be72308b7d
@ -105,14 +105,18 @@ pub fn expand_test_or_bench(
|
||||
|
||||
// Note: non-associated fn items are already handled by `expand_test_or_bench`
|
||||
if !matches!(item.kind, ast::ItemKind::Fn(_)) {
|
||||
cx.sess
|
||||
.parse_sess
|
||||
.span_diagnostic
|
||||
.struct_span_err(
|
||||
attr_sp,
|
||||
"the `#[test]` attribute may only be used on a non-associated function",
|
||||
)
|
||||
.note("the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
|
||||
let diag = &cx.sess.parse_sess.span_diagnostic;
|
||||
let msg = "the `#[test]` attribute may only be used on a non-associated function";
|
||||
let mut err = match item.kind {
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
|
||||
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
|
||||
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
|
||||
// reworked in the future to not need it, it'd be nice.
|
||||
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
|
||||
};
|
||||
err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
|
||||
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
|
||||
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
|
||||
.emit();
|
||||
|
@ -6,14 +6,14 @@ use crate::{
|
||||
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||
|
||||
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
def_id: DefId,
|
||||
body: &'tcx Body<'tcx>,
|
||||
) -> ConsumedAndBorrowedPlaces {
|
||||
let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
|
||||
let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx, fcx.param_env);
|
||||
expr_use_visitor.consume_body(fcx, def_id, body);
|
||||
expr_use_visitor.places
|
||||
}
|
||||
@ -36,14 +36,16 @@ pub(super) struct ConsumedAndBorrowedPlaces {
|
||||
/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
|
||||
/// record the parent expression, which is the point where the drop actually takes place.
|
||||
struct ExprUseDelegate<'tcx> {
|
||||
hir: Map<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
places: ConsumedAndBorrowedPlaces,
|
||||
}
|
||||
|
||||
impl<'tcx> ExprUseDelegate<'tcx> {
|
||||
fn new(hir: Map<'tcx>) -> Self {
|
||||
fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
Self {
|
||||
hir,
|
||||
tcx,
|
||||
param_env,
|
||||
places: ConsumedAndBorrowedPlaces {
|
||||
consumed: <_>::default(),
|
||||
borrowed: <_>::default(),
|
||||
@ -77,7 +79,7 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
|
||||
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
diag_expr_id: HirId,
|
||||
) {
|
||||
let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
|
||||
let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
|
||||
Some(parent) => parent,
|
||||
None => place_with_id.hir_id,
|
||||
};
|
||||
@ -107,11 +109,22 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
|
||||
assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
diag_expr_id: HirId,
|
||||
) {
|
||||
debug!("mutate {:?}; diag_expr_id={:?}", assignee_place, diag_expr_id);
|
||||
// Count mutations as a borrow.
|
||||
self.places
|
||||
.borrowed
|
||||
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
|
||||
debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}");
|
||||
// If the type being assigned needs dropped, then the mutation counts as a borrow
|
||||
// since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
|
||||
if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
|
||||
self.places
|
||||
.borrowed
|
||||
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
|
||||
}
|
||||
}
|
||||
|
||||
fn bind(
|
||||
&mut self,
|
||||
binding_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
diag_expr_id: HirId,
|
||||
) {
|
||||
debug!("bind {binding_place:?}; diag_expr_id={diag_expr_id:?}");
|
||||
}
|
||||
|
||||
fn fake_read(
|
||||
|
@ -51,6 +51,15 @@ pub trait Delegate<'tcx> {
|
||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
|
||||
|
||||
/// The path at `binding_place` is a binding that is being initialized.
|
||||
///
|
||||
/// This covers cases such as `let x = 42;`
|
||||
fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
|
||||
// Bindings can normally be treated as a regular assignment, so by default we
|
||||
// forward this to the mutate callback.
|
||||
self.mutate(binding_place, diag_expr_id)
|
||||
}
|
||||
|
||||
/// The `place` should be a fake read because of specified `cause`.
|
||||
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
|
||||
}
|
||||
@ -648,11 +657,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
|
||||
debug!("walk_pat: pat_ty={:?}", pat_ty);
|
||||
|
||||
// Each match binding is effectively an assignment to the
|
||||
// binding being produced.
|
||||
let def = Res::Local(canonical_id);
|
||||
if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
|
||||
delegate.mutate(binding_place, binding_place.hir_id);
|
||||
delegate.bind(binding_place, binding_place.hir_id);
|
||||
}
|
||||
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
|
@ -885,19 +885,18 @@ impl PartialOrd for Ordering {
|
||||
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
|
||||
/// the `<`, `<=`, `>`, and `>=` operators, respectively.
|
||||
///
|
||||
/// The methods of this trait must be consistent with each other and with those of `PartialEq` in
|
||||
/// the following sense:
|
||||
/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
|
||||
/// The following conditions must hold:
|
||||
///
|
||||
/// - `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
|
||||
/// - `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
|
||||
/// (ensured by the default implementation).
|
||||
/// - `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
|
||||
/// (ensured by the default implementation).
|
||||
/// - `a <= b` if and only if `a < b || a == b`
|
||||
/// (ensured by the default implementation).
|
||||
/// - `a >= b` if and only if `a > b || a == b`
|
||||
/// (ensured by the default implementation).
|
||||
/// - `a != b` if and only if `!(a == b)` (already part of `PartialEq`).
|
||||
/// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
|
||||
/// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
|
||||
/// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
|
||||
/// 4. `a <= b` if and only if `a < b || a == b`
|
||||
/// 5. `a >= b` if and only if `a > b || a == b`
|
||||
/// 6. `a != b` if and only if `!(a == b)`.
|
||||
///
|
||||
/// Conditions 2–5 above are ensured by the default implementation.
|
||||
/// Condition 6 is already ensured by [`PartialEq`].
|
||||
///
|
||||
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
|
||||
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's
|
||||
|
@ -1482,130 +1482,8 @@ mod remove_dir_impl {
|
||||
pub use crate::sys_common::fs::remove_dir_all;
|
||||
}
|
||||
|
||||
// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
mod remove_dir_impl {
|
||||
use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
|
||||
use crate::os::unix::prelude::{OwnedFd, RawFd};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::weak::weak;
|
||||
use crate::sys::{cvt, cvt_r};
|
||||
use libc::{c_char, c_int, DIR};
|
||||
|
||||
pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
|
||||
weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
|
||||
let fd = cvt_r(|| unsafe {
|
||||
openat.get().unwrap()(
|
||||
parent_fd.unwrap_or(libc::AT_FDCWD),
|
||||
p.as_ptr(),
|
||||
libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY,
|
||||
)
|
||||
})?;
|
||||
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
|
||||
}
|
||||
|
||||
fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
|
||||
weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
|
||||
let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) };
|
||||
if ptr.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let dirp = Dir(ptr);
|
||||
// file descriptor is automatically closed by libc::closedir() now, so give up ownership
|
||||
let new_parent_fd = dir_fd.into_raw_fd();
|
||||
// a valid root is not needed because we do not call any functions involving the full path
|
||||
// of the DirEntrys.
|
||||
let dummy_root = PathBuf::new();
|
||||
Ok((
|
||||
ReadDir {
|
||||
inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
|
||||
end_of_stream: false,
|
||||
},
|
||||
new_parent_fd,
|
||||
))
|
||||
}
|
||||
|
||||
fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
|
||||
weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
|
||||
|
||||
let pcstr = cstr(p)?;
|
||||
|
||||
// entry is expected to be a directory, open as such
|
||||
let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
|
||||
|
||||
// open the directory passing ownership of the fd
|
||||
let (dir, fd) = fdreaddir(fd)?;
|
||||
for child in dir {
|
||||
let child = child?;
|
||||
match child.entry.d_type {
|
||||
libc::DT_DIR => {
|
||||
remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
|
||||
}
|
||||
libc::DT_UNKNOWN => {
|
||||
match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })
|
||||
{
|
||||
// type unknown - try to unlink
|
||||
Err(err) if err.raw_os_error() == Some(libc::EPERM) => {
|
||||
// if the file is a directory unlink fails with EPERM
|
||||
remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
|
||||
}
|
||||
result => {
|
||||
result?;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// not a directory -> unlink
|
||||
cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unlink the directory after removing its contents
|
||||
cvt(unsafe {
|
||||
unlinkat.get().unwrap()(
|
||||
parent_fd.unwrap_or(libc::AT_FDCWD),
|
||||
pcstr.as_ptr(),
|
||||
libc::AT_REMOVEDIR,
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
|
||||
// We cannot just call remove_dir_all_recursive() here because that would not delete a passed
|
||||
// symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
|
||||
// into symlinks.
|
||||
let attr = lstat(p)?;
|
||||
if attr.file_type().is_symlink() {
|
||||
crate::fs::remove_file(p)
|
||||
} else {
|
||||
remove_dir_all_recursive(None, p)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
|
||||
weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
|
||||
if openat.get().is_some() {
|
||||
// openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
|
||||
remove_dir_all_modern(p)
|
||||
} else {
|
||||
// fall back to classic implementation
|
||||
crate::sys_common::fs::remove_dir_all(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modern implementation using openat(), unlinkat() and fdopendir()
|
||||
#[cfg(not(any(
|
||||
all(target_os = "macos", target_arch = "x86_64"),
|
||||
target_os = "redox",
|
||||
target_os = "espidf"
|
||||
)))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
|
||||
mod remove_dir_impl {
|
||||
use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
|
||||
use crate::ffi::CStr;
|
||||
@ -1615,7 +1493,49 @@ mod remove_dir_impl {
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::{cvt, cvt_r};
|
||||
|
||||
#[cfg(not(all(target_os = "macos", target_arch = "x86_64"),))]
|
||||
use libc::{fdopendir, openat, unlinkat};
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
use macos_weak::{fdopendir, openat, unlinkat};
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
mod macos_weak {
|
||||
use crate::sys::weak::weak;
|
||||
use libc::{c_char, c_int, DIR};
|
||||
|
||||
fn get_openat_fn() -> Option<unsafe extern "C" fn(c_int, *const c_char, c_int) -> c_int> {
|
||||
weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
|
||||
openat.get()
|
||||
}
|
||||
|
||||
pub fn has_openat() -> bool {
|
||||
get_openat_fn().is_some()
|
||||
}
|
||||
|
||||
pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
|
||||
get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| {
|
||||
crate::sys::unix::os::set_errno(libc::ENOSYS);
|
||||
-1
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn fdopendir(fd: c_int) -> *mut DIR {
|
||||
weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
|
||||
fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| {
|
||||
crate::sys::unix::os::set_errno(libc::ENOSYS);
|
||||
crate::ptr::null_mut()
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
|
||||
weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
|
||||
unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| {
|
||||
crate::sys::unix::os::set_errno(libc::ENOSYS);
|
||||
-1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
|
||||
let fd = cvt_r(|| unsafe {
|
||||
@ -1683,8 +1603,21 @@ mod remove_dir_impl {
|
||||
fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
|
||||
let pcstr = cstr(p)?;
|
||||
|
||||
// entry is expected to be a directory, open as such
|
||||
let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
|
||||
// try opening as directory
|
||||
let fd = match openat_nofollow_dironly(parent_fd, &pcstr) {
|
||||
Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
|
||||
// not a directory - don't traverse further
|
||||
return match parent_fd {
|
||||
// unlink...
|
||||
Some(parent_fd) => {
|
||||
cvt(unsafe { unlinkat(parent_fd, pcstr.as_ptr(), 0) }).map(drop)
|
||||
}
|
||||
// ...unless this was supposed to be the deletion root directory
|
||||
None => Err(err),
|
||||
};
|
||||
}
|
||||
result => result?,
|
||||
};
|
||||
|
||||
// open the directory passing ownership of the fd
|
||||
let (dir, fd) = fdreaddir(fd)?;
|
||||
@ -1697,19 +1630,13 @@ mod remove_dir_impl {
|
||||
Some(false) => {
|
||||
cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
|
||||
}
|
||||
None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) {
|
||||
// type unknown - try to unlink
|
||||
Err(err)
|
||||
if err.raw_os_error() == Some(libc::EISDIR)
|
||||
|| err.raw_os_error() == Some(libc::EPERM) =>
|
||||
{
|
||||
// if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else
|
||||
remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
|
||||
}
|
||||
result => {
|
||||
result?;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
|
||||
// if the process has the appropriate privileges. This however can causing orphaned
|
||||
// directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
|
||||
// into it first instead of trying to unlink() it.
|
||||
remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1720,7 +1647,7 @@ mod remove_dir_impl {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
|
||||
fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
|
||||
// We cannot just call remove_dir_all_recursive() here because that would not delete a passed
|
||||
// symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
|
||||
// into symlinks.
|
||||
@ -1731,4 +1658,20 @@ mod remove_dir_impl {
|
||||
remove_dir_all_recursive(None, p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
|
||||
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
|
||||
remove_dir_all_modern(p)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
|
||||
if macos_weak::has_openat() {
|
||||
// openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
|
||||
remove_dir_all_modern(p)
|
||||
} else {
|
||||
// fall back to classic implementation
|
||||
crate::sys_common::fs::remove_dir_all(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ The tracking issue for this feature is: [#44930]
|
||||
------------------------
|
||||
|
||||
The `c_variadic` language feature enables C-variadic functions to be
|
||||
defined in Rust. The may be called both from within Rust and via FFI.
|
||||
defined in Rust. They may be called both from within Rust and via FFI.
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
// FIXME(eholk): temporarily disabled while drop range tracking is disabled
|
||||
// (see generator_interior.rs:27)
|
||||
// ignore-test
|
||||
// compile-flags: --crate-type lib -Zdrop-tracking
|
||||
|
||||
use std::{cell::RefCell, fmt::Debug, rc::Rc};
|
||||
|
||||
|
19
src/test/ui/async-await/drop-and-assign.rs
Normal file
19
src/test/ui/async-await/drop-and-assign.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// edition:2021
|
||||
// compile-flags: -Zdrop-tracking
|
||||
// build-pass
|
||||
|
||||
struct A;
|
||||
impl Drop for A { fn drop(&mut self) {} }
|
||||
|
||||
pub async fn f() {
|
||||
let mut a = A;
|
||||
a = A;
|
||||
drop(a);
|
||||
async {}.await;
|
||||
}
|
||||
|
||||
fn assert_send<T: Send>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let _ = f();
|
||||
}
|
@ -2,10 +2,7 @@
|
||||
// Error message should pinpoint the type parameter T as needing to be bound
|
||||
// (rather than give a general error message)
|
||||
// edition:2018
|
||||
|
||||
// FIXME(eholk): temporarily disabled while drop range tracking is disabled
|
||||
// (see generator_interior.rs:27)
|
||||
// ignore-test
|
||||
// compile-flags: -Zdrop-tracking
|
||||
|
||||
async fn bar<T>() -> () {}
|
||||
|
||||
|
@ -1,35 +1,35 @@
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/unresolved_type_param.rs:9:5
|
||||
--> $DIR/unresolved_type_param.rs:10:5
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
||||
|
|
||||
note: the type is part of the `async fn` body because of this `await`
|
||||
--> $DIR/unresolved_type_param.rs:9:10
|
||||
--> $DIR/unresolved_type_param.rs:10:10
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/unresolved_type_param.rs:9:5
|
||||
--> $DIR/unresolved_type_param.rs:10:5
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
||||
|
|
||||
note: the type is part of the `async fn` body because of this `await`
|
||||
--> $DIR/unresolved_type_param.rs:9:10
|
||||
--> $DIR/unresolved_type_param.rs:10:10
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/unresolved_type_param.rs:9:5
|
||||
--> $DIR/unresolved_type_param.rs:10:5
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
||||
|
|
||||
note: the type is part of the `async fn` body because of this `await`
|
||||
--> $DIR/unresolved_type_param.rs:9:10
|
||||
--> $DIR/unresolved_type_param.rs:10:10
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^^^^
|
||||
|
@ -1,10 +1,6 @@
|
||||
// build-pass
|
||||
// compile-flags: -Zdrop-tracking
|
||||
|
||||
// FIXME(eholk): temporarily disabled while drop range tracking is disabled
|
||||
// (see generator_interior.rs:27)
|
||||
// ignore-test
|
||||
|
||||
// A test to ensure generators capture values that were conditionally dropped,
|
||||
// and also that values that are dropped along all paths to a yield do not get
|
||||
// included in the generator type.
|
||||
|
@ -1,8 +1,5 @@
|
||||
// check-pass
|
||||
|
||||
// FIXME(eholk): temporarily disabled while drop range tracking is disabled
|
||||
// (see generator_interior.rs:27)
|
||||
// ignore-test
|
||||
// compile-flags: -Zdrop-tracking
|
||||
|
||||
#![feature(negative_impls, generators)]
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
// FIXME(eholk): temporarily disabled while drop range tracking is disabled
|
||||
// (see generator_interior.rs:27)
|
||||
// ignore-test
|
||||
// compile-flags: -Zdrop-tracking
|
||||
|
||||
#![feature(negative_impls, generators)]
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: generator cannot be sent between threads safely
|
||||
--> $DIR/partial-drop.rs:12:5
|
||||
--> $DIR/partial-drop.rs:14:5
|
||||
|
|
||||
LL | assert_send(|| {
|
||||
| ^^^^^^^^^^^ generator is not `Send`
|
||||
|
|
||||
= help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
|
||||
= help: within `[generator@$DIR/partial-drop.rs:14:17: 20:6]`, the trait `Send` is not implemented for `Foo`
|
||||
note: generator is not `Send` as this value is used across a yield
|
||||
--> $DIR/partial-drop.rs:17:9
|
||||
--> $DIR/partial-drop.rs:19:9
|
||||
|
|
||||
LL | let guard = Bar { foo: Foo, x: 42 };
|
||||
| ----- has type `Bar` which is not `Send`
|
||||
@ -16,20 +16,20 @@ LL | yield;
|
||||
LL | });
|
||||
| - `guard` is later dropped here
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/partial-drop.rs:40:19
|
||||
--> $DIR/partial-drop.rs:42:19
|
||||
|
|
||||
LL | fn assert_send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `assert_send`
|
||||
|
||||
error: generator cannot be sent between threads safely
|
||||
--> $DIR/partial-drop.rs:20:5
|
||||
--> $DIR/partial-drop.rs:22:5
|
||||
|
|
||||
LL | assert_send(|| {
|
||||
| ^^^^^^^^^^^ generator is not `Send`
|
||||
|
|
||||
= help: within `[generator@$DIR/partial-drop.rs:20:17: 28:6]`, the trait `Send` is not implemented for `Foo`
|
||||
= help: within `[generator@$DIR/partial-drop.rs:22:17: 30:6]`, the trait `Send` is not implemented for `Foo`
|
||||
note: generator is not `Send` as this value is used across a yield
|
||||
--> $DIR/partial-drop.rs:27:9
|
||||
--> $DIR/partial-drop.rs:29:9
|
||||
|
|
||||
LL | let guard = Bar { foo: Foo, x: 42 };
|
||||
| ----- has type `Bar` which is not `Send`
|
||||
@ -39,20 +39,20 @@ LL | yield;
|
||||
LL | });
|
||||
| - `guard` is later dropped here
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/partial-drop.rs:40:19
|
||||
--> $DIR/partial-drop.rs:42:19
|
||||
|
|
||||
LL | fn assert_send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `assert_send`
|
||||
|
||||
error: generator cannot be sent between threads safely
|
||||
--> $DIR/partial-drop.rs:30:5
|
||||
--> $DIR/partial-drop.rs:32:5
|
||||
|
|
||||
LL | assert_send(|| {
|
||||
| ^^^^^^^^^^^ generator is not `Send`
|
||||
|
|
||||
= help: within `[generator@$DIR/partial-drop.rs:30:17: 37:6]`, the trait `Send` is not implemented for `Foo`
|
||||
= help: within `[generator@$DIR/partial-drop.rs:32:17: 39:6]`, the trait `Send` is not implemented for `Foo`
|
||||
note: generator is not `Send` as this value is used across a yield
|
||||
--> $DIR/partial-drop.rs:36:9
|
||||
--> $DIR/partial-drop.rs:38:9
|
||||
|
|
||||
LL | let guard = Bar { foo: Foo, x: 42 };
|
||||
| ----- has type `Bar` which is not `Send`
|
||||
@ -62,7 +62,7 @@ LL | yield;
|
||||
LL | });
|
||||
| - `guard` is later dropped here
|
||||
note: required by a bound in `assert_send`
|
||||
--> $DIR/partial-drop.rs:40:19
|
||||
--> $DIR/partial-drop.rs:42:19
|
||||
|
|
||||
LL | fn assert_send<T: Send>(_: T) {}
|
||||
| ^^^^ required by this bound in `assert_send`
|
||||
|
@ -1,14 +1,15 @@
|
||||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// Regression test for #47511: anonymous lifetimes can appear
|
||||
// unconstrained in a return type, but only if they appear just once
|
||||
// in the input, as the input to a projection.
|
||||
|
||||
fn f(_: X) -> X {
|
||||
//~^ ERROR return type references an anonymous lifetime
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn g<'a>(_: X<'a>) -> X<'a> {
|
||||
//~^ ERROR return type references lifetime `'a`, which is not constrained
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
|
||||
--> $DIR/issue-47511.rs:5:15
|
||||
--> $DIR/issue-47511.rs:8:15
|
||||
|
|
||||
LL | fn f(_: X) -> X {
|
||||
| ^
|
||||
@ -7,7 +7,7 @@ LL | fn f(_: X) -> X {
|
||||
= note: lifetimes appearing in an associated type are not considered constrained
|
||||
|
||||
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
|
||||
--> $DIR/issue-47511.rs:10:23
|
||||
--> $DIR/issue-47511.rs:12:23
|
||||
|
|
||||
LL | fn g<'a>(_: X<'a>) -> X<'a> {
|
||||
| ^^^^^
|
||||
|
@ -58,7 +58,7 @@ macro_rules! foo {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
|
||||
#[test] //~ WARN: the `#[test]` attribute may only be used on a non-associated function
|
||||
foo!();
|
||||
|
||||
// make sure it doesn't erroneously trigger on a real test
|
||||
|
@ -2,11 +2,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:3:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | mod test {}
|
||||
| ----------- expected a non-associated function, found a module
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -16,7 +15,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:6:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | / mod loooooooooooooong_teeeeeeeeeest {
|
||||
LL | | /*
|
||||
LL | | this is a comment
|
||||
@ -26,7 +25,6 @@ LL | | */
|
||||
LL | | }
|
||||
| |_- expected a non-associated function, found a module
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -36,11 +34,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:20:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | extern "C" {}
|
||||
| ------------- expected a non-associated function, found an extern block
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -50,11 +47,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:23:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | trait Foo {}
|
||||
| ------------ expected a non-associated function, found a trait
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -64,11 +60,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:26:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | impl Foo for i32 {}
|
||||
| ------------------- expected a non-associated function, found an implementation
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -78,11 +73,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:29:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | const FOO: i32 = -1_i32;
|
||||
| ------------------------ expected a non-associated function, found a constant item
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -92,11 +86,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:32:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | static BAR: u64 = 10_000_u64;
|
||||
| ----------------------------- expected a non-associated function, found a static item
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -106,13 +99,12 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:35:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | / enum MyUnit {
|
||||
LL | | Unit,
|
||||
LL | | }
|
||||
| |_- expected a non-associated function, found an enum
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -122,11 +114,10 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:40:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | struct NewI32(i32);
|
||||
| ------------------- expected a non-associated function, found a struct
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -136,14 +127,13 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:43:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | / union Spooky {
|
||||
LL | | x: i32,
|
||||
LL | | y: u32,
|
||||
LL | | }
|
||||
| |_- expected a non-associated function, found a union
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
@ -153,7 +143,7 @@ error: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:50:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | #[derive(Copy, Clone, Debug)]
|
||||
LL | / struct MoreAttrs {
|
||||
LL | | a: i32,
|
||||
@ -161,25 +151,23 @@ LL | | b: u64,
|
||||
LL | | }
|
||||
| |_- expected a non-associated function, found a struct
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error: the `#[test]` attribute may only be used on a non-associated function
|
||||
warning: the `#[test]` attribute may only be used on a non-associated function
|
||||
--> $DIR/test-on-not-fn.rs:61:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
LL | foo!();
|
||||
| ------- expected a non-associated function, found an item macro invocation
|
||||
|
|
||||
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
|
||||
help: replace with conditional compilation to make the item only exist when tests are being run
|
||||
|
|
||||
LL | #[cfg(test)]
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 11 previous errors; 1 warning emitted
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user