about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-04-28 08:20:19 +0000
committerbors <bors@rust-lang.org>2021-04-28 08:20:19 +0000
commit76a04dd3f8b2500d9e524dca122814fd5a3e25e4 (patch)
tree368723e31133e7227bffb7e175ff204730d01eaa
parent855c2d130fb70da1643cf8f696c7aad7537aef34 (diff)
parent7ebe5b9e4d3edae756aa50e72d61ce88da5b773c (diff)
downloadrust-76a04dd3f8b2500d9e524dca122814fd5a3e25e4.tar.gz
rust-76a04dd3f8b2500d9e524dca122814fd5a3e25e4.zip
Auto merge of #84644 - JohnTitor:rollup-nzq9rjz, r=JohnTitor
Rollup of 5 pull requests

Successful merges:

 - #84529 (Improve coverage spans for chained function calls)
 - #84616 (Fix empty dom toggle)
 - #84622 (Make traits with GATs not object safe)
 - #84624 (Make sentence in env::args_os' docs plain and simple)
 - #84642 (Stabilize vec_extend_from_within)

Failed merges:

 - #84636 (rustdoc: change aliases attribute to data-aliases)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs8
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs7
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/std/src/env.rs2
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs205
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt89
-rw-r--r--src/test/run-make-fulldeps/coverage/try_error_result.rs84
-rw-r--r--src/test/rustdoc/empty-impls.rs19
-rw-r--r--src/test/rustdoc/issue-53812.rs10
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path.rs3
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-67510-pass.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-67510-pass.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-76535.stderr37
-rw-r--r--src/test/ui/generic-associated-types/issue-78671.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-78671.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.rs3
-rw-r--r--src/test/ui/generic-associated-types/issue-79422.stderr38
-rw-r--r--src/test/ui/generic-associated-types/trait-objects.rs16
-rw-r--r--src/test/ui/generic-associated-types/trait-objects.stderr18
26 files changed, 499 insertions, 136 deletions
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 00dec3b355f..c9b73c68209 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -670,6 +670,9 @@ pub enum ObjectSafetyViolation {
 
     /// Associated const.
     AssocConst(Symbol, Span),
+
+    /// GAT
+    GAT(Symbol, Span),
 }
 
 impl ObjectSafetyViolation {
@@ -715,6 +718,9 @@ impl ObjectSafetyViolation {
                 format!("it contains associated `const` `{}`", name).into()
             }
             ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
+            ObjectSafetyViolation::GAT(name, _) => {
+                format!("it contains the generic associated type `{}`", name).into()
+            }
         }
     }
 
@@ -773,6 +779,7 @@ impl ObjectSafetyViolation {
                 );
             }
             ObjectSafetyViolation::AssocConst(name, _)
+            | ObjectSafetyViolation::GAT(name, _)
             | ObjectSafetyViolation::Method(name, ..) => {
                 err.help(&format!("consider moving `{}` to another trait", name));
             }
@@ -786,6 +793,7 @@ impl ObjectSafetyViolation {
             ObjectSafetyViolation::SupertraitSelf(spans)
             | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
             ObjectSafetyViolation::AssocConst(_, span)
+            | ObjectSafetyViolation::GAT(_, span)
             | ObjectSafetyViolation::Method(_, _, span)
                 if *span != DUMMY_SP =>
             {
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index 249f5e835cd..2041109eb38 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -717,11 +717,21 @@ pub(super) fn filtered_terminator_span(
         | TerminatorKind::FalseEdge { .. }
         | TerminatorKind::Goto { .. } => None,
 
+        // Call `func` operand can have a more specific span when part of a chain of calls
+        | TerminatorKind::Call { ref func, .. } => {
+            let mut span = terminator.source_info.span;
+            if let mir::Operand::Constant(box constant) = func {
+                if constant.span.lo() > span.lo() {
+                    span = span.with_lo(constant.span.lo());
+                }
+            }
+            Some(function_source_span(span, body_span))
+        }
+
         // Retain spans from all other terminators
         TerminatorKind::Resume
         | TerminatorKind::Abort
         | TerminatorKind::Return
-        | TerminatorKind::Call { .. }
         | TerminatorKind::Yield { .. }
         | TerminatorKind::GeneratorDrop
         | TerminatorKind::FalseUnwind { .. }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index ac5ec24eeee..d5e1bd3f9ea 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -132,6 +132,14 @@ fn object_safety_violations_for_trait(
             .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
     );
 
+    violations.extend(
+        tcx.associated_items(trait_def_id)
+            .in_definition_order()
+            .filter(|item| item.kind == ty::AssocKind::Type)
+            .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
+            .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)),
+    );
+
     debug!(
         "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
         trait_def_id, violations
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 31685a012ca..e338a21b603 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -462,12 +462,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         for assoc_type in assoc_types {
             if !tcx.generics_of(assoc_type).params.is_empty() {
-                // FIXME(generic_associated_types) generate placeholders to
-                // extend the trait substs.
-                tcx.sess.span_fatal(
+                tcx.sess.delay_span_bug(
                     obligation.cause.span,
-                    "generic associated types in trait objects are not supported yet",
+                    "GATs in trait object shouldn't have been considered",
                 );
+                return Err(SelectionError::Unimplemented);
             }
             // This maybe belongs in wf, but that can't (doesn't) handle
             // higher-ranked things.
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 3a5dcec668f..15308a4469b 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -76,7 +76,6 @@
 #![cfg_attr(test, feature(test))]
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(allocator_api)]
-#![feature(vec_extend_from_within)]
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_windows)]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index e459442dfcf..85c9446689e 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2124,8 +2124,6 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// ## Examples
     ///
     /// ```
-    /// #![feature(vec_extend_from_within)]
-    ///
     /// let mut vec = vec![0, 1, 2, 3, 4];
     ///
     /// vec.extend_from_within(2..);
@@ -2137,7 +2135,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// vec.extend_from_within(4..8);
     /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]);
     /// ```
-    #[unstable(feature = "vec_extend_from_within", issue = "81656")]
+    #[stable(feature = "vec_extend_from_within", since = "1.53.0")]
     pub fn extend_from_within<R>(&mut self, src: R)
     where
         R: RangeBounds<usize>,
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 7e1194cc4aa..25a83a0b014 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -20,7 +20,6 @@
 #![feature(vecdeque_binary_search)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
-#![feature(vec_extend_from_within)]
 #![feature(vec_spare_capacity)]
 #![feature(string_remove_matches)]
 
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 116a37249e3..d20bb585841 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -752,7 +752,7 @@ pub fn args() -> Args {
 /// does on macOS and Windows.
 ///
 /// Note that the returned iterator will not check if the arguments to the
-/// process are valid Unicode. To ensure UTF-8 validity,
+/// process are valid Unicode. If you want to panic on invalid UTF-8,
 /// use the [`args`] function instead.
 ///
 /// # Examples
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e39652c6dd5..45412f55c15 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -82,6 +82,10 @@ impl Buffer {
         self.buffer.push_str(s);
     }
 
+    crate fn push_buffer(&mut self, other: Buffer) {
+        self.buffer.push_str(&other.buffer);
+    }
+
     // Intended for consumption by write! and writeln! (std::fmt) but without
     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
     // import).
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 19b8dd15ad0..518dbc6eeb3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1281,99 +1281,6 @@ fn render_impl(
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
     let mut close_tags = String::new();
 
-    if render_mode == RenderMode::Normal {
-        let id = cx.derive_id(match i.inner_impl().trait_ {
-            Some(ref t) => {
-                if is_on_foreign_type {
-                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
-                } else {
-                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
-                }
-            }
-            None => "impl".to_string(),
-        });
-        let aliases = if aliases.is_empty() {
-            String::new()
-        } else {
-            format!(" aliases=\"{}\"", aliases.join(","))
-        };
-        if let Some(use_absolute) = use_absolute {
-            write!(
-                w,
-                "<details class=\"rustdoc-toggle implementors-toggle\" open>\
-                     <summary>\
-                         <h3 id=\"{}\" class=\"impl\"{}>\
-                             <code class=\"in-band\">",
-                id, aliases
-            );
-            close_tags.insert_str(0, "</details>");
-            write!(w, "{}", i.inner_impl().print(use_absolute, cx));
-            if show_def_docs {
-                for it in &i.inner_impl().items {
-                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
-                        w.write_str("<span class=\"where fmt-newline\">  ");
-                        assoc_type(
-                            w,
-                            it,
-                            &[],
-                            Some(&tydef.type_),
-                            AssocItemLink::Anchor(None),
-                            "",
-                            cx,
-                        );
-                        w.write_str(";</span>");
-                    }
-                }
-            }
-            w.write_str("</code>");
-        } else {
-            write!(
-                w,
-                "<details class=\"rustdoc-toggle implementors-toggle\" open>\
-                     <summary>\
-                         <h3 id=\"{}\" class=\"impl\"{}>\
-                             <code class=\"in-band\">{}</code>",
-                id,
-                aliases,
-                i.inner_impl().print(false, cx)
-            );
-            close_tags.insert_str(0, "</details>");
-        }
-        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-        render_stability_since_raw(
-            w,
-            i.impl_item.stable_since(tcx).as_deref(),
-            i.impl_item.const_stable_since(tcx).as_deref(),
-            outer_version,
-            outer_const_version,
-        );
-        write_srclink(cx, &i.impl_item, w);
-        w.write_str("</h3></summary>");
-
-        if trait_.is_some() {
-            if let Some(portability) = portability(&i.impl_item, Some(parent)) {
-                write!(w, "<div class=\"item-info\">{}</div>", portability);
-            }
-        }
-
-        if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
-            let mut ids = cx.id_map.borrow_mut();
-            write!(
-                w,
-                "<div class=\"docblock\">{}</div>",
-                Markdown(
-                    &*dox,
-                    &i.impl_item.links(cx),
-                    &mut ids,
-                    cx.shared.codes,
-                    cx.shared.edition(),
-                    &cx.shared.playground
-                )
-                .into_string()
-            );
-        }
-    }
-
     fn doc_impl_item(
         w: &mut Buffer,
         cx: &Context<'_>,
@@ -1549,11 +1456,10 @@ fn render_impl(
         }
     }
 
-    w.write_str("<div class=\"impl-items\">");
-    close_tags.insert_str(0, "</div>");
+    let mut impl_items = Buffer::empty_from(w);
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
-            w,
+            &mut impl_items,
             cx,
             trait_item,
             if trait_.is_some() { &i.impl_item } else { parent },
@@ -1609,7 +1515,7 @@ fn render_impl(
     if show_default_items {
         if let Some(t) = trait_ {
             render_default_items(
-                w,
+                &mut impl_items,
                 cx,
                 &t.trait_,
                 &i.inner_impl(),
@@ -1621,6 +1527,111 @@ fn render_impl(
             );
         }
     }
+    let details_str = if impl_items.is_empty() {
+        ""
+    } else {
+        "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+    };
+    if render_mode == RenderMode::Normal {
+        let id = cx.derive_id(match i.inner_impl().trait_ {
+            Some(ref t) => {
+                if is_on_foreign_type {
+                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
+                } else {
+                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
+                }
+            }
+            None => "impl".to_string(),
+        });
+        let aliases = if aliases.is_empty() {
+            String::new()
+        } else {
+            format!(" aliases=\"{}\"", aliases.join(","))
+        };
+        if let Some(use_absolute) = use_absolute {
+            write!(
+                w,
+                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
+                details_str, id, aliases
+            );
+            if !impl_items.is_empty() {
+                close_tags.insert_str(0, "</details>");
+            }
+            write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+            if show_def_docs {
+                for it in &i.inner_impl().items {
+                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
+                        w.write_str("<span class=\"where fmt-newline\">  ");
+                        assoc_type(
+                            w,
+                            it,
+                            &[],
+                            Some(&tydef.type_),
+                            AssocItemLink::Anchor(None),
+                            "",
+                            cx,
+                        );
+                        w.write_str(";</span>");
+                    }
+                }
+            }
+            w.write_str("</code>");
+        } else {
+            write!(
+                w,
+                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
+                details_str,
+                id,
+                aliases,
+                i.inner_impl().print(false, cx)
+            );
+            if !impl_items.is_empty() {
+                close_tags.insert_str(0, "</details>");
+            }
+        }
+        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+        render_stability_since_raw(
+            w,
+            i.impl_item.stable_since(tcx).as_deref(),
+            i.impl_item.const_stable_since(tcx).as_deref(),
+            outer_version,
+            outer_const_version,
+        );
+        write_srclink(cx, &i.impl_item, w);
+        if impl_items.is_empty() {
+            w.write_str("</h3>");
+        } else {
+            w.write_str("</h3></summary>");
+        }
+
+        if trait_.is_some() {
+            if let Some(portability) = portability(&i.impl_item, Some(parent)) {
+                write!(w, "<div class=\"item-info\">{}</div>", portability);
+            }
+        }
+
+        if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
+            let mut ids = cx.id_map.borrow_mut();
+            write!(
+                w,
+                "<div class=\"docblock\">{}</div>",
+                Markdown(
+                    &*dox,
+                    &i.impl_item.links(cx),
+                    &mut ids,
+                    cx.shared.codes,
+                    cx.shared.edition(),
+                    &cx.shared.playground
+                )
+                .into_string()
+            );
+        }
+    }
+    if !impl_items.is_empty() {
+        w.write_str("<div class=\"impl-items\">");
+        w.push_buffer(impl_items);
+        close_tags.insert_str(0, "</div>");
+    }
     w.write_str(&close_tags);
 }
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
index c9ebffde039..9fca52451ed 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
@@ -9,7 +9,7 @@
     9|       |    }
    10|      6|}
    11|       |
-   12|      1|fn main() -> Result<(),()> {
+   12|      1|fn test1() -> Result<(),()> {
    13|      1|    let mut
    14|      1|        countdown = 10
    15|       |    ;
@@ -35,4 +35,91 @@
    34|       |    }
    35|      0|    Ok(())
    36|      1|}
+   37|       |
+   38|       |struct Thing1;
+   39|       |impl Thing1 {
+   40|     18|    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+   41|     18|        if return_error {
+   42|      1|            Err(())
+   43|       |        } else {
+   44|     17|            Ok(Thing2{})
+   45|       |        }
+   46|     18|    }
+   47|       |}
+   48|       |
+   49|       |struct Thing2;
+   50|       |impl Thing2 {
+   51|     17|    fn call(&self, return_error: bool) -> Result<u32,()> {
+   52|     17|        if return_error {
+   53|      2|            Err(())
+   54|       |        } else {
+   55|     15|            Ok(57)
+   56|       |        }
+   57|     17|    }
+   58|       |}
+   59|       |
+   60|      1|fn test2() -> Result<(),()> {
+   61|      1|    let thing1 = Thing1{};
+   62|      1|    let mut
+   63|      1|        countdown = 10
+   64|       |    ;
+   65|       |    for
+   66|      6|        _
+   67|       |    in
+   68|      6|        0..10
+   69|       |    {
+   70|      6|        countdown
+   71|      6|            -= 1
+   72|      6|        ;
+   73|      6|        if
+   74|      6|            countdown < 5
+   75|       |        {
+   76|      1|            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+                                                            ^0
+   77|      1|            thing1
+   78|      1|                .
+   79|      1|                get_thing_2(/*return_error=*/ false)
+   80|      0|                ?
+   81|       |                .
+   82|      1|                call(/*return_error=*/ true)
+   83|      1|                .
+   84|      1|                expect_err(
+   85|      1|                    "call should fail"
+   86|      1|                );
+   87|      1|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+                              ^0                                                ^0                          ^0
+   88|      0|            assert_eq!(val, 57);
+   89|      0|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+   90|      0|            assert_eq!(val, 57);
+   91|       |        }
+   92|       |        else
+   93|       |        {
+   94|      5|            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+                                                                               ^0                             ^0
+   95|      5|            assert_eq!(val, 57);
+   96|      5|            let val = thing1
+   97|      5|                .get_thing_2(/*return_error=*/ false)?
+                                                                   ^0
+   98|      5|                .call(/*return_error=*/ false)?;
+                                                            ^0
+   99|      5|            assert_eq!(val, 57);
+  100|      5|            let val = thing1
+  101|      5|                .get_thing_2(/*return_error=*/ false)
+  102|      0|                ?
+  103|      5|                .call(/*return_error=*/ false)
+  104|      0|                ?
+  105|       |                ;
+  106|      5|            assert_eq!(val, 57);
+  107|       |        }
+  108|       |    }
+  109|      0|    Ok(())
+  110|      1|}
+  111|       |
+  112|      1|fn main() -> Result<(),()> {
+  113|      1|    test1().expect_err("test1 should fail");
+  114|      1|    test2()
+  115|      1|    ?
+  116|       |    ;
+  117|      0|    Ok(())
+  118|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make-fulldeps/coverage/try_error_result.rs
index 13c455172dd..cd0acf72302 100644
--- a/src/test/run-make-fulldeps/coverage/try_error_result.rs
+++ b/src/test/run-make-fulldeps/coverage/try_error_result.rs
@@ -9,7 +9,7 @@ fn call(return_error: bool) -> Result<(),()> {
     }
 }
 
-fn main() -> Result<(),()> {
+fn test1() -> Result<(),()> {
     let mut
         countdown = 10
     ;
@@ -34,3 +34,85 @@ fn main() -> Result<(),()> {
     }
     Ok(())
 }
+
+struct Thing1;
+impl Thing1 {
+    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(Thing2{})
+        }
+    }
+}
+
+struct Thing2;
+impl Thing2 {
+    fn call(&self, return_error: bool) -> Result<u32,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(57)
+        }
+    }
+}
+
+fn test2() -> Result<(),()> {
+    let thing1 = Thing1{};
+    let mut
+        countdown = 10
+    ;
+    for
+        _
+    in
+        0..10
+    {
+        countdown
+            -= 1
+        ;
+        if
+            countdown < 5
+        {
+            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+            thing1
+                .
+                get_thing_2(/*return_error=*/ false)
+                ?
+                .
+                call(/*return_error=*/ true)
+                .
+                expect_err(
+                    "call should fail"
+                );
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+            assert_eq!(val, 57);
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+        }
+        else
+        {
+            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)?
+                .call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)
+                ?
+                .call(/*return_error=*/ false)
+                ?
+                ;
+            assert_eq!(val, 57);
+        }
+    }
+    Ok(())
+}
+
+fn main() -> Result<(),()> {
+    test1().expect_err("test1 should fail");
+    test2()
+    ?
+    ;
+    Ok(())
+}
diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs
new file mode 100644
index 00000000000..86dec32e625
--- /dev/null
+++ b/src/test/rustdoc/empty-impls.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+pub struct Foo;
+
+pub trait EmptyTrait {}
+
+// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+impl EmptyTrait for Foo {}
+
+pub trait NotEmpty {
+    fn foo(&self);
+}
+
+// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+impl NotEmpty for Foo {
+    fn foo(&self) {}
+}
diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs
index daebe059f8e..ddc14e68675 100644
--- a/src/test/rustdoc/issue-53812.rs
+++ b/src/test/rustdoc/issue-53812.rs
@@ -12,9 +12,9 @@ macro_rules! array_impls {
     }
 }
 
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
index 2dbd1840dec..6527eb47504 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(generic_associated_types)]
   //~^ WARNING: the feature `generic_associated_types` is incomplete
 #![feature(associated_type_defaults)]
@@ -22,6 +20,7 @@ impl<T> Foo for Fooer<T> {
 }
 
 fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
+//~^ the trait `Foo` cannot be made into an object
 
 
 fn main() {
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
index f3769827f04..49dfce8b4bd 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr
@@ -1,5 +1,5 @@
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/gat-in-trait-path.rs:3:12
+  --> $DIR/gat-in-trait-path.rs:1:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
 
-warning: 1 warning emitted
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/gat-in-trait-path.rs:22:13
+   |
+LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+   = help: consider moving `A` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/gat-in-trait-path.rs:6:10
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     type A<'a> where Self: 'a;
+   |          ^ ...because it contains the generic associated type `A`
+
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs
index ff38b3e93eb..6ee865072ae 100644
--- a/src/test/ui/generic-associated-types/issue-67510-pass.rs
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(generic_associated_types)]
   //~^ WARNING: the feature `generic_associated_types` is incomplete
 
@@ -8,5 +6,6 @@ trait X {
 }
 
 fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
+//~^ ERROR the trait `X` cannot be made into an object
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
index 0fbf704df76..65998afa7f9 100644
--- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr
+++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr
@@ -1,5 +1,5 @@
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-67510-pass.rs:3:12
+  --> $DIR/issue-67510-pass.rs:1:12
    |
 LL | #![feature(generic_associated_types)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
 
-warning: 1 warning emitted
+error[E0038]: the trait `X` cannot be made into an object
+  --> $DIR/issue-67510-pass.rs:8:19
+   |
+LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |
+   = help: consider moving `Y` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-67510-pass.rs:5:10
+   |
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     type Y<'a>;
+   |          ^ ...because it contains the generic associated type `Y`
+
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs
index 5e73a882986..9643c82db77 100644
--- a/src/test/ui/generic-associated-types/issue-76535.rs
+++ b/src/test/ui/generic-associated-types/issue-76535.rs
@@ -36,4 +36,6 @@ impl SuperTrait for SuperStruct {
 
 fn main() {
     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+    //~^ ERROR the trait `SuperTrait` cannot be made into an object
+    //~^^ ERROR the trait `SuperTrait` cannot be made into an object
 }
diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr
index 17661e0d90a..d31560f12f0 100644
--- a/src/test/ui/generic-associated-types/issue-76535.stderr
+++ b/src/test/ui/generic-associated-types/issue-76535.stderr
@@ -23,6 +23,39 @@ help: use angle brackets to add missing lifetime argument
 LL |     type SubType<'a><'a>: SubTrait;
    |                 ^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error[E0038]: the trait `SuperTrait` cannot be made into an object
+  --> $DIR/issue-76535.rs:38:14
+   |
+LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |
+   = help: consider moving `SubType` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-76535.rs:7:10
+   |
+LL | pub trait SuperTrait {
+   |           ---------- this trait cannot be made into an object...
+LL |     type SubType<'a>: SubTrait;
+   |          ^^^^^^^ ...because it contains the generic associated type `SubType`
+
+error[E0038]: the trait `SuperTrait` cannot be made into an object
+  --> $DIR/issue-76535.rs:38:57
+   |
+LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |
+   = help: consider moving `SubType` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-76535.rs:7:10
+   |
+LL | pub trait SuperTrait {
+   |           ---------- this trait cannot be made into an object...
+LL |     type SubType<'a>: SubTrait;
+   |          ^^^^^^^ ...because it contains the generic associated type `SubType`
+   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
+   = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-78671.rs b/src/test/ui/generic-associated-types/issue-78671.rs
index 1b02aac8bcb..4e47d3c6655 100644
--- a/src/test/ui/generic-associated-types/issue-78671.rs
+++ b/src/test/ui/generic-associated-types/issue-78671.rs
@@ -7,6 +7,7 @@ trait CollectionFamily {
 }
 fn floatify() {
     Box::new(Family) as &dyn CollectionFamily<Member=usize>
+    //~^ the trait `CollectionFamily` cannot be made into an object
 }
 
 struct Family;
diff --git a/src/test/ui/generic-associated-types/issue-78671.stderr b/src/test/ui/generic-associated-types/issue-78671.stderr
index 7a9aced5bea..c9febfb59af 100644
--- a/src/test/ui/generic-associated-types/issue-78671.stderr
+++ b/src/test/ui/generic-associated-types/issue-78671.stderr
@@ -14,6 +14,22 @@ help: use angle brackets to add missing type argument
 LL |     type Member<T><T>;
    |                ^^^
 
-error: aborting due to previous error
+error[E0038]: the trait `CollectionFamily` cannot be made into an object
+  --> $DIR/issue-78671.rs:9:25
+   |
+LL |     Box::new(Family) as &dyn CollectionFamily<Member=usize>
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
+   |
+   = help: consider moving `Member` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-78671.rs:5:10
+   |
+LL | trait CollectionFamily {
+   |       ---------------- this trait cannot be made into an object...
+LL |     type Member<T>;
+   |          ^^^^^^ ...because it contains the generic associated type `Member`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs
index aeb33ca5464..b2ba3c24abb 100644
--- a/src/test/ui/generic-associated-types/issue-79422.rs
+++ b/src/test/ui/generic-associated-types/issue-79422.rs
@@ -42,5 +42,6 @@ impl<K, V: Default> MapLike<K, V> for Source {
 fn main() {
     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-    //~^^ ERROR type mismatch resolving
+    //~^^ the trait `MapLike` cannot be made into an object
+    //~^^ the trait `MapLike` cannot be made into an object
 }
diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr
index a119bff03e2..4973ae19729 100644
--- a/src/test/ui/generic-associated-types/issue-79422.stderr
+++ b/src/test/ui/generic-associated-types/issue-79422.stderr
@@ -14,17 +14,39 @@ help: use angle brackets to add missing lifetime argument
 LL |     type VRefCont<'a><'a>: RefCont<'a, V>;
    |                  ^^^^
 
-error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
+error[E0038]: the trait `MapLike` cannot be made into an object
+  --> $DIR/issue-79422.rs:44:12
+   |
+LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |
+   = help: consider moving `VRefCont` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-79422.rs:21:10
+   |
+LL | trait MapLike<K, V> {
+   |       ------- this trait cannot be made into an object...
+LL |     type VRefCont<'a>: RefCont<'a, V>;
+   |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
+
+error[E0038]: the trait `MapLike` cannot be made into an object
   --> $DIR/issue-79422.rs:43:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |
+   = help: consider moving `VRefCont` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-79422.rs:21:10
    |
-   = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
-                 found reference `&'static u8`
-   = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
+LL | trait MapLike<K, V> {
+   |       ------- this trait cannot be made into an object...
+LL |     type VRefCont<'a>: RefCont<'a, V>;
+   |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
+   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
+   = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0271.
-For more information about an error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/trait-objects.rs b/src/test/ui/generic-associated-types/trait-objects.rs
new file mode 100644
index 00000000000..997a550b0ef
--- /dev/null
+++ b/src/test/ui/generic-associated-types/trait-objects.rs
@@ -0,0 +1,16 @@
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait StreamingIterator {
+    type Item<'a> where Self: 'a;
+    fn size_hint(&self) -> (usize, Option<usize>);
+    // Uncommenting makes `StreamingIterator` not object safe
+//    fn next(&mut self) -> Self::Item<'_>;
+}
+
+fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
+    //~^ the trait `StreamingIterator` cannot be made into an object
+    x.size_hint().0
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr
new file mode 100644
index 00000000000..a8f1768ba26
--- /dev/null
+++ b/src/test/ui/generic-associated-types/trait-objects.stderr
@@ -0,0 +1,18 @@
+error[E0038]: the trait `StreamingIterator` cannot be made into an object
+  --> $DIR/trait-objects.rs:11:16
+   |
+LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |
+   = help: consider moving `Item` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-objects.rs:5:10
+   |
+LL | trait StreamingIterator {
+   |       ----------------- this trait cannot be made into an object...
+LL |     type Item<'a> where Self: 'a;
+   |          ^^^^ ...because it contains the generic associated type `Item`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.