about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-05 04:56:35 +0000
committerbors <bors@rust-lang.org>2022-03-05 04:56:35 +0000
commitbe72308b7dfcb83925674b68e280f5f625b3100d (patch)
tree8cad004b408f8bf8d3ccd173ac2adb251581045e
parent8c93948d6e9e09abfffc53d0b863ece16cde7286 (diff)
parente8a0a4e2affe1897ac09255735d3ce3b8d89d5fa (diff)
downloadrust-be72308b7dfcb83925674b68e280f5f625b3100d.tar.gz
rust-be72308b7dfcb83925674b68e280f5f625b3100d.zip
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
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs20
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs35
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs13
-rw-r--r--library/core/src/cmp.rs25
-rw-r--r--library/std/src/sys/unix/fs.rs205
-rw-r--r--src/doc/unstable-book/src/language-features/c-variadic.md2
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.rs6
-rw-r--r--src/test/ui/async-await/drop-and-assign.rs19
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs5
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr12
-rw-r--r--src/test/ui/generator/drop-control-flow.rs4
-rw-r--r--src/test/ui/generator/issue-57478.rs5
-rw-r--r--src/test/ui/generator/partial-drop.rs4
-rw-r--r--src/test/ui/generator/partial-drop.stderr24
-rw-r--r--src/test/ui/issues/issue-47511.rs5
-rw-r--r--src/test/ui/issues/issue-47511.stderr4
-rw-r--r--src/test/ui/test-attrs/test-on-not-fn.rs2
-rw-r--r--src/test/ui/test-attrs/test-on-not-fn.stderr40
18 files changed, 194 insertions, 236 deletions
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index e658631d090..0c2d20b8f2d 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -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();
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index 03d3b23bb23..40ee6d863b5 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -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(
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index db1c80ae433..8c19bbd3214 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -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.
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index a3e77479911..ddaeb9eca97 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -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:
-///
-/// - `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`).
+/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
+/// The following conditions must hold:
+///
+/// 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
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 8bd0b9b14af..0851f512fd0 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1482,140 +1482,60 @@ 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"))]
+// Modern implementation using openat(), unlinkat() and fdopendir()
+#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
 mod remove_dir_impl {
-    use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
+    use super::{cstr, lstat, Dir, DirEntry, 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);
+    #[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};
 
-        let pcstr = cstr(p)?;
+    #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+    mod macos_weak {
+        use crate::sys::weak::weak;
+        use libc::{c_char, c_int, DIR};
 
-        // entry is expected to be a directory, open as such
-        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+        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()
+        }
 
-        // 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) })?;
-                }
-            }
+        pub fn has_openat() -> bool {
+            get_openat_fn().is_some()
         }
 
-        // 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(())
-    }
+        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
+            })
+        }
 
-    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 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 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)
+        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
+            })
         }
     }
-}
-
-// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(
-    all(target_os = "macos", target_arch = "x86_64"),
-    target_os = "redox",
-    target_os = "espidf"
-)))]
-mod remove_dir_impl {
-    use super::{cstr, lstat, Dir, DirEntry, 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::{cvt, cvt_r};
-    use libc::{fdopendir, openat, unlinkat};
 
     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)
+        }
+    }
 }
diff --git a/src/doc/unstable-book/src/language-features/c-variadic.md b/src/doc/unstable-book/src/language-features/c-variadic.md
index 9e7968d906f..001c1bfa9ec 100644
--- a/src/doc/unstable-book/src/language-features/c-variadic.md
+++ b/src/doc/unstable-book/src/language-features/c-variadic.md
@@ -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
 
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index a1a05c0acba..d7f8d7ac546 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -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};
 
diff --git a/src/test/ui/async-await/drop-and-assign.rs b/src/test/ui/async-await/drop-and-assign.rs
new file mode 100644
index 00000000000..fa3f3303677
--- /dev/null
+++ b/src/test/ui/async-await/drop-and-assign.rs
@@ -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();
+}
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 187356ca140..6d6d8061491 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -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>() -> () {}
 
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index d19a3226ef9..7236c681f34 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -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;
    |          ^^^^^^
diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs
index 914a7d71dc4..d383680002f 100644
--- a/src/test/ui/generator/drop-control-flow.rs
+++ b/src/test/ui/generator/drop-control-flow.rs
@@ -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.
diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs
index 5c23ecbae32..91407ea1844 100644
--- a/src/test/ui/generator/issue-57478.rs
+++ b/src/test/ui/generator/issue-57478.rs
@@ -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)]
 
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
index e89e4b61bbf..c872fb7f3e6 100644
--- a/src/test/ui/generator/partial-drop.rs
+++ b/src/test/ui/generator/partial-drop.rs
@@ -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)]
 
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
index 9a1b0734d8c..16b34c917ec 100644
--- a/src/test/ui/generator/partial-drop.stderr
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -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`
diff --git a/src/test/ui/issues/issue-47511.rs b/src/test/ui/issues/issue-47511.rs
index 0f33b52577b..98c141b6c6a 100644
--- a/src/test/ui/issues/issue-47511.rs
+++ b/src/test/ui/issues/issue-47511.rs
@@ -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!()
 }
 
diff --git a/src/test/ui/issues/issue-47511.stderr b/src/test/ui/issues/issue-47511.stderr
index 4473c0e68cf..5b84f7ed62c 100644
--- a/src/test/ui/issues/issue-47511.stderr
+++ b/src/test/ui/issues/issue-47511.stderr
@@ -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> {
    |                       ^^^^^
diff --git a/src/test/ui/test-attrs/test-on-not-fn.rs b/src/test/ui/test-attrs/test-on-not-fn.rs
index b2f681c01d1..a460480afb1 100644
--- a/src/test/ui/test-attrs/test-on-not-fn.rs
+++ b/src/test/ui/test-attrs/test-on-not-fn.rs
@@ -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
diff --git a/src/test/ui/test-attrs/test-on-not-fn.stderr b/src/test/ui/test-attrs/test-on-not-fn.stderr
index dd693cf316d..23efd5bc0d9 100644
--- a/src/test/ui/test-attrs/test-on-not-fn.stderr
+++ b/src/test/ui/test-attrs/test-on-not-fn.stderr
@@ -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