about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-04-21 16:14:10 +0000
committerbors <bors@rust-lang.org>2025-04-21 16:14:10 +0000
commit8f2819b0e3428d0aee05fa60e91e0211c2aea053 (patch)
tree8319a2108ee04851fcec93d82f74f798453677eb
parentc8f94230282a8e8c1148f3e657f0199aad909228 (diff)
parent77325f5200097718ac87863c96388c15efc3a629 (diff)
downloadrust-8f2819b0e3428d0aee05fa60e91e0211c2aea053.tar.gz
rust-8f2819b0e3428d0aee05fa60e91e0211c2aea053.zip
Auto merge of #140122 - ChrisDenton:rollup-qsj6xu0, r=ChrisDenton
Rollup of 8 pull requests

Successful merges:

 - #139946 (fix missing word in comment)
 - #139982 (SystemTime doc tweaks)
 - #140009 (docs(LocalKey<T>): clarify that T's Drop shouldn't panic)
 - #140021 (Don't ICE on pending obligations from deep normalization in a loop)
 - #140029 (Relocate tests in `tests/ui`)
 - #140030 (Fix autodiff debug builds)
 - #140120 (Use `output_base_dir` for `mir_dump_dir`)
 - #140121 (Document why CodeStats::type_sizes is public)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs3
-rw-r--r--compiler/rustc_session/src/code_stats.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs10
-rw-r--r--library/core/src/any.rs4
-rw-r--r--library/std/src/rt.rs2
-rw-r--r--library/std/src/thread/local.rs6
-rw-r--r--library/std/src/time.rs5
-rw-r--r--src/tools/compiletest/src/runtest.rs13
-rw-r--r--src/tools/compiletest/src/runtest/mir_opt.rs4
-rw-r--r--src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr2
-rw-r--r--tests/crashes/133868.rs13
-rw-r--r--tests/ui/borrowck/writing-to-immutable-vec.rs (renamed from tests/ui/writing-to-immutable-vec.rs)0
-rw-r--r--tests/ui/borrowck/writing-to-immutable-vec.stderr (renamed from tests/ui/writing-to-immutable-vec.stderr)0
-rw-r--r--tests/ui/deref-patterns/deref-non-pointer.rs (renamed from tests/ui/deref-non-pointer.rs)0
-rw-r--r--tests/ui/deref-patterns/deref-non-pointer.stderr (renamed from tests/ui/deref-non-pointer.stderr)0
-rw-r--r--tests/ui/lazy-and-or.rs12
-rw-r--r--tests/ui/list.rs9
-rw-r--r--tests/ui/minus-string.rs1
-rw-r--r--tests/ui/or-patterns/lazy-and-or.rs25
-rw-r--r--tests/ui/recursion/recursive-enum-box.rs21
-rw-r--r--tests/ui/runtime/rt-explody-panic-payloads.rs2
-rw-r--r--tests/ui/traits/deep-norm-pending.rs24
-rw-r--r--tests/ui/traits/deep-norm-pending.stderr130
-rw-r--r--tests/ui/typeck/minus-string.rs7
-rw-r--r--tests/ui/typeck/minus-string.stderr (renamed from tests/ui/minus-string.stderr)6
26 files changed, 240 insertions, 63 deletions
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index b1b6f10e0fe..d7690a96e10 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -254,8 +254,9 @@ where
             always_export_generics,
         );
 
-        // We can't differentiate something that got inlined.
+        // We can't differentiate a function that got inlined.
         let autodiff_active = cfg!(llvm_enzyme)
+            && matches!(mono_item, MonoItem::Fn(_))
             && cx
                 .tcx
                 .codegen_fn_attrs(mono_item.def_id())
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 6b18d450e9e..80603b4a156 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -72,6 +72,8 @@ pub struct TypeSizeInfo {
 
 #[derive(Default)]
 pub struct CodeStats {
+    /// The hash set that actually holds all the type size information.
+    /// The field is public for use in external tools. See #139876.
     pub type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 4ac45172a0e..7551ac5aa97 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -77,7 +77,15 @@ impl<'tcx> At<'_, 'tcx> {
                 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
             let errors = fulfill_cx.select_all_or_error(self.infcx);
             let value = self.infcx.resolve_vars_if_possible(value);
-            if errors.is_empty() { Ok(value) } else { Err(errors) }
+            if errors.is_empty() {
+                Ok(value)
+            } else {
+                // Drop pending obligations, since deep normalization may happen
+                // in a loop and we don't want to trigger the assertion on the next
+                // iteration due to pending ambiguous obligations we've left over.
+                let _ = fulfill_cx.collect_remaining_errors(self.infcx);
+                Err(errors)
+            }
         }
     }
 }
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 10f2a11d558..7aa3f3c6d74 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -772,8 +772,8 @@ impl hash::Hash for TypeId {
         //   (especially given the previous point about the lower 64 bits being
         //   high quality on their own).
         // - It is correct to do so -- only hashing a subset of `self` is still
-        //   with an `Eq` implementation that considers the entire value, as
-        //   ours does.
+        //   compatible with an `Eq` implementation that considers the entire
+        //   value, as ours does.
         self.t.1.hash(state);
     }
 }
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 3a22a16cb16..9737b2f5bfe 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -46,7 +46,7 @@ macro_rules! rtprintpanic {
 macro_rules! rtabort {
     ($($t:tt)*) => {
         {
-            rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
+            rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
             crate::sys::abort_internal();
         }
     }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index d5a5d10205d..7cd44873313 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -22,12 +22,16 @@ use crate::fmt;
 ///
 /// Initialization is dynamically performed on the first call to a setter (e.g.
 /// [`with`]) within a thread, and values that implement [`Drop`] get
-/// destructed when a thread exits. Some caveats apply, which are explained below.
+/// destructed when a thread exits. Some platform-specific caveats apply, which
+/// are explained below.
+/// Note that, should the destructor panics, the whole process will be [aborted].
 ///
 /// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
 /// `LocalKey` in this way may cause panics, aborts or infinite recursion on
 /// the first call to `with`.
 ///
+/// [aborted]: crate::process::abort
+///
 /// # Single-thread Synchronization
 ///
 /// Though there is no potential race with other threads, it is still possible to
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 5ab71413586..03af35e809c 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -205,8 +205,8 @@ pub struct Instant(time::Instant);
 ///            println!("{}", elapsed.as_secs());
 ///        }
 ///        Err(e) => {
-///            // an error occurred!
-///            println!("Error: {e:?}");
+///            // the system clock went backwards!
+///            println!("Great Scott! {e:?}");
 ///        }
 ///    }
 /// }
@@ -245,6 +245,7 @@ pub struct Instant(time::Instant);
 /// > structure cannot represent the new point in time.
 ///
 /// [`add`]: SystemTime::add
+/// [`UNIX_EPOCH`]: SystemTime::UNIX_EPOCH
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTime(time::SystemTime);
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index d11f5c1a3a6..cc09463c358 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1395,14 +1395,6 @@ impl<'test> TestCx<'test> {
         matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
     }
 
-    fn get_mir_dump_dir(&self) -> Utf8PathBuf {
-        let mut mir_dump_dir = self.config.build_test_suite_root.clone();
-        debug!("input_file: {}", self.testpaths.file);
-        mir_dump_dir.push(&self.testpaths.relative_dir);
-        mir_dump_dir.push(self.testpaths.file.file_stem().unwrap());
-        mir_dump_dir
-    }
-
     fn make_compile_args(
         &self,
         input_file: &Utf8Path,
@@ -1511,10 +1503,7 @@ impl<'test> TestCx<'test> {
         }
 
         let set_mir_dump_dir = |rustc: &mut Command| {
-            let mir_dump_dir = self.get_mir_dump_dir();
-            remove_and_create_dir_all(&mir_dump_dir).unwrap_or_else(|e| {
-                panic!("failed to remove and recreate output directory `{mir_dump_dir}`: {e}")
-            });
+            let mir_dump_dir = self.output_base_dir();
             let mut dir_opt = "-Zdump-mir-dir=".to_string();
             dir_opt.push_str(mir_dump_dir.as_str());
             debug!("dir_opt: {:?}", dir_opt);
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index ded6a68fe58..efdb131bf14 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -56,7 +56,7 @@ impl TestCx<'_> {
                 self.diff_mir_files(from_file.into(), after.into())
             } else {
                 let mut output_file = Utf8PathBuf::new();
-                output_file.push(self.get_mir_dump_dir());
+                output_file.push(self.output_base_dir());
                 output_file.push(&from_file);
                 debug!("comparing the contents of: {} with {:?}", output_file, expected_file);
                 if !output_file.exists() {
@@ -100,7 +100,7 @@ impl TestCx<'_> {
 
     fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String {
         let to_full_path = |path: Utf8PathBuf| {
-            let full = self.get_mir_dump_dir().join(&path);
+            let full = self.output_base_dir().join(&path);
             if !full.exists() {
                 panic!(
                     "the mir dump file for {} does not exist (requested in {})",
diff --git a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
index aadb9976609..1dcdb4a3996 100644
--- a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
@@ -1,7 +1,7 @@
 
 thread $NAME panicked at tests/fail/panic/tls_macro_const_drop_panic.rs:LL:CC:
 ow
-fatal runtime error: thread local panicked on drop
+fatal runtime error: thread local panicked on drop, aborting
 error: abnormal termination: the program aborted execution
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
index 546ee7e1ed2..7e4907abd93 100644
--- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
@@ -1,7 +1,7 @@
 
 thread $NAME panicked at tests/fail/panic/tls_macro_drop_panic.rs:LL:CC:
 ow
-fatal runtime error: thread local panicked on drop
+fatal runtime error: thread local panicked on drop, aborting
 error: abnormal termination: the program aborted execution
 
 error: aborting due to 1 previous error
diff --git a/tests/crashes/133868.rs b/tests/crashes/133868.rs
deleted file mode 100644
index dc25cb9df28..00000000000
--- a/tests/crashes/133868.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #133868
-
-trait Foo {
-    type Assoc;
-}
-
-trait Bar {
-    fn method() -> impl Sized;
-}
-impl<T> Bar for T where <T as Foo>::Assoc: Sized
-{
-    fn method() {}
-}
diff --git a/tests/ui/writing-to-immutable-vec.rs b/tests/ui/borrowck/writing-to-immutable-vec.rs
index dbcc3f0bbe9..dbcc3f0bbe9 100644
--- a/tests/ui/writing-to-immutable-vec.rs
+++ b/tests/ui/borrowck/writing-to-immutable-vec.rs
diff --git a/tests/ui/writing-to-immutable-vec.stderr b/tests/ui/borrowck/writing-to-immutable-vec.stderr
index 06e1684dffe..06e1684dffe 100644
--- a/tests/ui/writing-to-immutable-vec.stderr
+++ b/tests/ui/borrowck/writing-to-immutable-vec.stderr
diff --git a/tests/ui/deref-non-pointer.rs b/tests/ui/deref-patterns/deref-non-pointer.rs
index 82ab355e697..82ab355e697 100644
--- a/tests/ui/deref-non-pointer.rs
+++ b/tests/ui/deref-patterns/deref-non-pointer.rs
diff --git a/tests/ui/deref-non-pointer.stderr b/tests/ui/deref-patterns/deref-non-pointer.stderr
index 3ee354819e5..3ee354819e5 100644
--- a/tests/ui/deref-non-pointer.stderr
+++ b/tests/ui/deref-patterns/deref-non-pointer.stderr
diff --git a/tests/ui/lazy-and-or.rs b/tests/ui/lazy-and-or.rs
deleted file mode 100644
index f9dbeb68959..00000000000
--- a/tests/ui/lazy-and-or.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ run-pass
-
-fn incr(x: &mut isize) -> bool { *x += 1; assert!((false)); return false; }
-
-pub fn main() {
-    let x = 1 == 2 || 3 == 3;
-    assert!((x));
-    let mut y: isize = 10;
-    println!("{}", x || incr(&mut y));
-    assert_eq!(y, 10);
-    if true && x { assert!((true)); } else { assert!((false)); }
-}
diff --git a/tests/ui/list.rs b/tests/ui/list.rs
deleted file mode 100644
index 443c4c9f28f..00000000000
--- a/tests/ui/list.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-#![allow(non_camel_case_types)]
-
-enum list { #[allow(dead_code)] cons(isize, Box<list>), nil, }
-
-pub fn main() {
-    list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
-}
diff --git a/tests/ui/minus-string.rs b/tests/ui/minus-string.rs
deleted file mode 100644
index b83347b937e..00000000000
--- a/tests/ui/minus-string.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn main() { -"foo".to_string(); } //~ ERROR cannot apply unary operator `-` to type `String`
diff --git a/tests/ui/or-patterns/lazy-and-or.rs b/tests/ui/or-patterns/lazy-and-or.rs
new file mode 100644
index 00000000000..3d69553132b
--- /dev/null
+++ b/tests/ui/or-patterns/lazy-and-or.rs
@@ -0,0 +1,25 @@
+//@ run-pass
+// This test verifies the short-circuiting behavior of logical operators `||` and `&&`.
+// It ensures that the right-hand expression is not evaluated when the left-hand
+// expression is sufficient to determine the result.
+
+fn would_panic_if_called(x: &mut isize) -> bool {
+    *x += 1;
+    assert!(false, "This function should never be called due to short-circuiting");
+    false
+}
+
+fn main() {
+    let x = 1 == 2 || 3 == 3;
+    assert!(x);
+
+    let mut y: isize = 10;
+    println!("Result of short-circuit: {}", x || would_panic_if_called(&mut y));
+    assert_eq!(y, 10, "y should remain 10 if short-circuiting works correctly");
+
+    if true && x {
+        assert!(true);
+    } else {
+        assert!(false, "This branch should not be reached");
+    }
+}
diff --git a/tests/ui/recursion/recursive-enum-box.rs b/tests/ui/recursion/recursive-enum-box.rs
new file mode 100644
index 00000000000..540b0c55360
--- /dev/null
+++ b/tests/ui/recursion/recursive-enum-box.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+// A smoke test for recursive enum structures using Box<T>.
+// This test constructs a linked list-like structure to exercise memory allocation and ownership.
+// Originally introduced in 2010, this is one of Rust’s earliest test cases.
+
+#![allow(dead_code)]
+
+enum List {
+    Cons(isize, Box<List>),
+    Nil,
+}
+
+fn main() {
+    List::Cons(
+        10,
+        Box::new(List::Cons(
+            11,
+            Box::new(List::Cons(12, Box::new(List::Nil))),
+        )),
+    );
+}
diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs
index c177fd260ed..d564a26ca73 100644
--- a/tests/ui/runtime/rt-explody-panic-payloads.rs
+++ b/tests/ui/runtime/rt-explody-panic-payloads.rs
@@ -27,6 +27,6 @@ fn main() {
             // by QEMU in the stderr whenever a core dump happens. Remove it before the check.
             v.strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n").unwrap_or(v)
         })
-        .map(|v| { v.ends_with("fatal runtime error: drop of the panic payload panicked\n") })
+        .map(|v| v.ends_with("fatal runtime error: drop of the panic payload panicked, aborting\n"))
         .unwrap_or(false));
 }
diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/deep-norm-pending.rs
new file mode 100644
index 00000000000..f56c3cfa3ea
--- /dev/null
+++ b/tests/ui/traits/deep-norm-pending.rs
@@ -0,0 +1,24 @@
+trait Foo {
+    type Assoc;
+}
+
+trait Bar {
+    fn method() -> impl Sized;
+    //~^ ERROR the trait bound `T: Foo` is not satisfied
+}
+impl<T> Bar for T
+//~^ ERROR the trait bound `T: Foo` is not satisfied
+//~| ERROR the trait bound `T: Foo` is not satisfied
+where
+    <T as Foo>::Assoc: Sized,
+{
+    fn method() {}
+    //~^ ERROR the trait bound `T: Foo` is not satisfied
+    //~| ERROR the trait bound `T: Foo` is not satisfied
+    //~| ERROR the trait bound `T: Foo` is not satisfied
+    //~| ERROR the trait bound `T: Foo` is not satisfied
+    //~| ERROR the trait bound `T: Foo` is not satisfied
+    //~| ERROR the trait bound `T: Foo` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/deep-norm-pending.stderr
new file mode 100644
index 00000000000..b95b9d7f4ae
--- /dev/null
+++ b/tests/ui/traits/deep-norm-pending.stderr
@@ -0,0 +1,130 @@
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:5
+   |
+LL |     fn method() {}
+   |     ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:9:1
+   |
+LL | / impl<T> Bar for T
+LL | |
+LL | |
+LL | | where
+LL | |     <T as Foo>::Assoc: Sized,
+   | |_____________________________^ the trait `Foo` is not implemented for `T`
+   |
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:9:1
+   |
+LL | / impl<T> Bar for T
+LL | |
+LL | |
+LL | | where
+...  |
+LL | | }
+   | |_^ the trait `Foo` is not implemented for `T`
+   |
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:5
+   |
+LL |     fn method() {}
+   |     ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:5
+   |
+LL |     fn method() {}
+   |     ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+note: required for `T` to implement `Bar`
+  --> $DIR/deep-norm-pending.rs:9:9
+   |
+LL | impl<T> Bar for T
+   |         ^^^     ^
+...
+LL |     <T as Foo>::Assoc: Sized,
+   |                        ----- unsatisfied trait bound introduced here
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:5
+   |
+LL |     fn method() {}
+   |     ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:6:20
+   |
+LL |     fn method() -> impl Sized;
+   |                    ^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+note: required for `T` to implement `Bar`
+  --> $DIR/deep-norm-pending.rs:9:9
+   |
+LL | impl<T> Bar for T
+   |         ^^^     ^
+...
+LL |     <T as Foo>::Assoc: Sized,
+   |                        ----- unsatisfied trait bound introduced here
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:5
+   |
+LL |     fn method() {}
+   |     ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+  --> $DIR/deep-norm-pending.rs:15:8
+   |
+LL |     fn method() {}
+   |        ^^^^^^ the trait `Foo` is not implemented for `T`
+   |
+help: consider further restricting type parameter `T` with trait `Foo`
+   |
+LL |     <T as Foo>::Assoc: Sized, T: Foo
+   |                               ++++++
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/typeck/minus-string.rs b/tests/ui/typeck/minus-string.rs
new file mode 100644
index 00000000000..1c0f73a3713
--- /dev/null
+++ b/tests/ui/typeck/minus-string.rs
@@ -0,0 +1,7 @@
+// Regression test for issue #813.
+// This ensures that the unary negation operator `-` cannot be applied to an owned `String`.
+// Previously, due to a type-checking bug, this was mistakenly accepted by the compiler.
+
+fn main() {
+    -"foo".to_string(); //~ ERROR cannot apply unary operator `-` to type `String`
+}
diff --git a/tests/ui/minus-string.stderr b/tests/ui/typeck/minus-string.stderr
index 153965c810e..d2ebcd01ff9 100644
--- a/tests/ui/minus-string.stderr
+++ b/tests/ui/typeck/minus-string.stderr
@@ -1,8 +1,8 @@
 error[E0600]: cannot apply unary operator `-` to type `String`
-  --> $DIR/minus-string.rs:1:13
+  --> $DIR/minus-string.rs:6:5
    |
-LL | fn main() { -"foo".to_string(); }
-   |             ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
+LL |     -"foo".to_string();
+   |     ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
    |
 note: the foreign item type `String` doesn't implement `Neg`
   --> $SRC_DIR/alloc/src/string.rs:LL:COL