about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/etc/htmldocck.py47
-rw-r--r--src/librustdoc/html/render/mod.rs7
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css6
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css1
-rw-r--r--src/librustdoc/html/static/css/themes/light.css1
-rw-r--r--src/librustdoc/passes/stripper.rs5
-rw-r--r--src/test/rustdoc/empty-impl-block.rs20
-rw-r--r--src/test/ui/cast/casts-issue-46365.rs3
-rw-r--r--src/test/ui/impl-trait/universal_wrong_hrtb.rs8
-rw-r--r--src/test/ui/impl-trait/universal_wrong_hrtb.stderr14
-rw-r--r--src/test/ui/parser/labeled-no-colon-expr.stderr6
-rw-r--r--src/test/ui/parser/recover-labeled-non-block-expr.fixed27
-rw-r--r--src/test/ui/parser/recover-labeled-non-block-expr.rs26
-rw-r--r--src/test/ui/parser/recover-labeled-non-block-expr.stderr80
-rw-r--r--src/test/ui/suggestions/issue-97704.fixed19
-rw-r--r--src/test/ui/suggestions/issue-97704.rs19
-rw-r--r--src/test/ui/suggestions/issue-97704.stderr15
17 files changed, 271 insertions, 33 deletions
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 5eb70ab13db..f762e389005 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -94,6 +94,10 @@ There are a number of supported commands:
   in the specified file. The number of occurrences must match the given
   count.
 
+* `@count PATH XPATH TEXT COUNT` checks for the occurrence of the given XPath
+  with the given text in the specified file. The number of occurrences must
+  match the given count.
+
 * `@snapshot NAME PATH XPATH` creates a snapshot test named NAME.
   A snapshot test captures a subtree of the DOM, at the location
   determined by the XPath, and compares it to a pre-recorded value
@@ -382,9 +386,10 @@ def check_tree_attr(tree, path, attr, pat, regexp):
     return ret
 
 
-def check_tree_text(tree, path, pat, regexp):
+# Returns the number of occurences matching the regex (`regexp`) and the text (`pat`).
+def check_tree_text(tree, path, pat, regexp, stop_at_first):
     path = normalize_xpath(path)
-    ret = False
+    match_count = 0
     try:
         for e in tree.findall(path):
             try:
@@ -392,13 +397,14 @@ def check_tree_text(tree, path, pat, regexp):
             except KeyError:
                 continue
             else:
-                ret = check_string(value, pat, regexp)
-                if ret:
-                    break
+                if check_string(value, pat, regexp):
+                    match_count += 1
+                    if stop_at_first:
+                        break
     except Exception:
         print('Failed to get path "{}"'.format(path))
         raise
-    return ret
+    return match_count
 
 
 def get_tree_count(tree, path):
@@ -518,6 +524,19 @@ def print_err(lineno, context, err, message=None):
         stderr("\t{}".format(context))
 
 
+def get_nb_matching_elements(cache, c, regexp, stop_at_first):
+    tree = cache.get_tree(c.args[0])
+    pat, sep, attr = c.args[1].partition('/@')
+    if sep:  # attribute
+        tree = cache.get_tree(c.args[0])
+        return check_tree_attr(tree, pat, attr, c.args[2], False)
+    else:  # normalized text
+        pat = c.args[1]
+        if pat.endswith('/text()'):
+            pat = pat[:-7]
+        return check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first)
+
+
 ERR_COUNT = 0
 
 
@@ -538,16 +557,7 @@ def check_command(c, cache):
                 ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp)
             elif len(c.args) == 3:  # @has/matches <path> <pat> <match> = XML tree test
                 cerr = "`XPATH PATTERN` did not match"
-                tree = cache.get_tree(c.args[0])
-                pat, sep, attr = c.args[1].partition('/@')
-                if sep:  # attribute
-                    tree = cache.get_tree(c.args[0])
-                    ret = check_tree_attr(tree, pat, attr, c.args[2], regexp)
-                else:  # normalized text
-                    pat = c.args[1]
-                    if pat.endswith('/text()'):
-                        pat = pat[:-7]
-                    ret = check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp)
+                ret = get_nb_matching_elements(cache, c, regexp, True) != 0
             else:
                 raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
 
@@ -557,6 +567,11 @@ def check_command(c, cache):
                 found = get_tree_count(cache.get_tree(c.args[0]), c.args[1])
                 cerr = "Expected {} occurrences but found {}".format(expected, found)
                 ret = expected == found
+            elif len(c.args) == 4:  # @count <path> <pat> <text> <count> = count test
+                expected = int(c.args[3])
+                found = get_nb_matching_elements(cache, c, False, False)
+                cerr = "Expected {} occurrences but found {}".format(expected, found)
+                ret = found == expected
             else:
                 raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 23ce634cf28..cb887d16906 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1600,6 +1600,13 @@ fn render_impl(
         }
 
         if let Some(ref dox) = i.impl_item.collapsed_doc_value() {
+            if trait_.is_none() && i.inner_impl().items.is_empty() {
+                w.write_str(
+                    "<div class=\"item-info\">\
+                    <div class=\"stab empty-impl\">This impl block contains no items.</div>
+                </div>",
+                );
+            }
             write!(
                 w,
                 "<div class=\"docblock\">{}</div>",
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 7303cecc0d6..8e0521d9ad6 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -281,9 +281,13 @@ details.undocumented > summary::before {
 	color: #000;
 }
 
+/* Created this empty rule to satisfy the theme checks. */
+.stab.empty-impl {}
+
 .stab.unstable,
 .stab.deprecated,
-.stab.portability {
+.stab.portability,
+.stab.empty-impl {
 	color: #c5c5c5;
 	background: #314559 !important;
 	border-style: none !important;
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 34a4f446b56..071ad006ed3 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -266,6 +266,7 @@ details.undocumented > summary::before {
 	color: #ddd;
 }
 
+.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
 .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
 .stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index aa6ad2f5473..5c3789bf463 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -255,6 +255,7 @@ details.undocumented > summary::before {
 	color: #000;
 }
 
+.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
 .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
 .stab.portability { background: #F3DFFF; border-color: #b07bdb; }
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index d5db919dc4b..0fd124e6154 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -124,8 +124,9 @@ pub(crate) struct ImplStripper<'a> {
 impl<'a> DocFolder for ImplStripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if let clean::ImplItem(ref imp) = *i.kind {
-            // emptied none trait impls can be stripped
-            if imp.trait_.is_none() && imp.items.is_empty() {
+            // Impl blocks can be skipped if they are: empty; not a trait impl; and have no
+            // documentation.
+            if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
                 return None;
             }
             if let Some(did) = imp.for_.def_id(self.cache) {
diff --git a/src/test/rustdoc/empty-impl-block.rs b/src/test/rustdoc/empty-impl-block.rs
new file mode 100644
index 00000000000..6a2a254f63a
--- /dev/null
+++ b/src/test/rustdoc/empty-impl-block.rs
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// @has - '//*[@class="docblock"]' 'Hello empty impl block!'
+// @has - '//*[@class="item-info"]' 'This impl block contains no items.'
+/// Hello empty impl block!
+impl Foo {}
+// We ensure that this empty impl block without doc isn't rendered.
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1
+impl Foo {}
+
+// Just to ensure that empty trait impl blocks are rendered.
+pub struct Another;
+pub trait Bar {}
+
+// @has 'foo/struct.Another.html'
+// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Another'
+impl Bar for Another {}
diff --git a/src/test/ui/cast/casts-issue-46365.rs b/src/test/ui/cast/casts-issue-46365.rs
index a2205b718c1..50aa1a856a7 100644
--- a/src/test/ui/cast/casts-issue-46365.rs
+++ b/src/test/ui/cast/casts-issue-46365.rs
@@ -3,5 +3,6 @@ struct Lorem {
 }
 
 fn main() {
-    let _foo: *mut Lorem = core::ptr::NonNull::dangling().as_ptr(); // no error here
+    // Testing `as` casts, so deliberately not using `ptr::null`.
+    let _foo: *mut Lorem = 0 as *mut _; // no error here
 }
diff --git a/src/test/ui/impl-trait/universal_wrong_hrtb.rs b/src/test/ui/impl-trait/universal_wrong_hrtb.rs
new file mode 100644
index 00000000000..b9551c2ceb0
--- /dev/null
+++ b/src/test/ui/impl-trait/universal_wrong_hrtb.rs
@@ -0,0 +1,8 @@
+trait Trait<'a> {
+    type Assoc;
+}
+
+fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
+//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/universal_wrong_hrtb.stderr b/src/test/ui/impl-trait/universal_wrong_hrtb.stderr
new file mode 100644
index 00000000000..37eb8dfa1a1
--- /dev/null
+++ b/src/test/ui/impl-trait/universal_wrong_hrtb.stderr
@@ -0,0 +1,14 @@
+error: `impl Trait` can only mention lifetimes bound at the fn or impl level
+  --> $DIR/universal_wrong_hrtb.rs:5:73
+   |
+LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
+   |                                                                         ^^
+   |
+note: lifetime declared here
+  --> $DIR/universal_wrong_hrtb.rs:5:39
+   |
+LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
+   |                                       ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/labeled-no-colon-expr.stderr b/src/test/ui/parser/labeled-no-colon-expr.stderr
index 26884dc5d74..5c9597c440c 100644
--- a/src/test/ui/parser/labeled-no-colon-expr.stderr
+++ b/src/test/ui/parser/labeled-no-colon-expr.stderr
@@ -47,6 +47,12 @@ error: expected `while`, `for`, `loop` or `{` after a label
    |
 LL |     'l4 0;
    |         ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider removing the label
+   |
+LL -     'l4 0;
+LL +     0;
+   | 
 
 error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:8:9
diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.fixed b/src/test/ui/parser/recover-labeled-non-block-expr.fixed
new file mode 100644
index 00000000000..fe546a71971
--- /dev/null
+++ b/src/test/ui/parser/recover-labeled-non-block-expr.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+#![feature(label_break_value)]
+fn main() {
+    let _ = 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+    match () { () => {}, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+    'label: { match () { () => break 'label, } }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+    #[allow(unused_labels)]
+    'label: { match () { () => 'lp: loop { break 'lp 0 }, } }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+    let x = 1;
+    let _i = 'label: { match x { //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+        0 => 42,
+        1 if false => break 'label 17,
+        1 => {
+            if true {
+                break 'label 13
+            } else {
+                break 'label 0;
+            }
+        }
+        _ => 1,
+    } };
+
+    let other = 3;
+    let _val = 'label: { (1, if other == 3 { break 'label (2, 3) } else { other }) }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+}
diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.rs b/src/test/ui/parser/recover-labeled-non-block-expr.rs
index be92170acf0..35862e2eef9 100644
--- a/src/test/ui/parser/recover-labeled-non-block-expr.rs
+++ b/src/test/ui/parser/recover-labeled-non-block-expr.rs
@@ -1,5 +1,27 @@
+// run-rustfix
+#![feature(label_break_value)]
 fn main() {
-    'label: 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+    let _ = 'label: 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
 
-    let _recovery_witness: () = 0; //~ ERROR mismatched types
+    'label: match () { () => {}, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+    'label: match () { () => break 'label, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+    #[allow(unused_labels)]
+    'label: match () { () => 'lp: loop { break 'lp 0 }, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+    let x = 1;
+    let _i = 'label: match x { //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+        0 => 42,
+        1 if false => break 'label 17,
+        1 => {
+            if true {
+                break 'label 13
+            } else {
+                break 'label 0;
+            }
+        }
+        _ => 1,
+    };
+
+    let other = 3;
+    let _val = 'label: (1, if other == 3 { break 'label (2, 3) } else { other }); //~ ERROR expected `while`, `for`, `loop` or `{` after a label
 }
diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.stderr b/src/test/ui/parser/recover-labeled-non-block-expr.stderr
index 771a915288c..767389c4808 100644
--- a/src/test/ui/parser/recover-labeled-non-block-expr.stderr
+++ b/src/test/ui/parser/recover-labeled-non-block-expr.stderr
@@ -1,17 +1,75 @@
 error: expected `while`, `for`, `loop` or `{` after a label
-  --> $DIR/recover-labeled-non-block-expr.rs:2:13
+  --> $DIR/recover-labeled-non-block-expr.rs:4:21
    |
-LL |     'label: 1 + 1;
-   |             ^ expected `while`, `for`, `loop` or `{` after a label
+LL |     let _ = 'label: 1 + 1;
+   |                     ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider removing the label
+   |
+LL -     let _ = 'label: 1 + 1;
+LL +     let _ = 1 + 1;
+   | 
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/recover-labeled-non-block-expr.rs:6:13
+   |
+LL |     'label: match () { () => {}, };
+   |             ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider removing the label
+   |
+LL -     'label: match () { () => {}, };
+LL +     match () { () => {}, };
+   | 
 
-error[E0308]: mismatched types
-  --> $DIR/recover-labeled-non-block-expr.rs:4:33
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/recover-labeled-non-block-expr.rs:7:13
+   |
+LL |     'label: match () { () => break 'label, };
+   |             ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider enclosing expression in a block
+   |
+LL |     'label: { match () { () => break 'label, } };
+   |             +                                  +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/recover-labeled-non-block-expr.rs:9:13
+   |
+LL |     'label: match () { () => 'lp: loop { break 'lp 0 }, };
+   |             ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider enclosing expression in a block
+   |
+LL |     'label: { match () { () => 'lp: loop { break 'lp 0 }, } };
+   |             +                                               +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/recover-labeled-non-block-expr.rs:12:22
+   |
+LL |     let _i = 'label: match x {
+   |                      ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider enclosing expression in a block
+   |
+LL ~     let _i = 'label: { match x {
+LL |         0 => 42,
+LL |         1 if false => break 'label 17,
+LL |         1 => {
+LL |             if true {
+LL |                 break 'label 13
+ ...
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/recover-labeled-non-block-expr.rs:26:24
+   |
+LL |     let _val = 'label: (1, if other == 3 { break 'label (2, 3) } else { other });
+   |                        ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: consider enclosing expression in a block
    |
-LL |     let _recovery_witness: () = 0;
-   |                            --   ^ expected `()`, found integer
-   |                            |
-   |                            expected due to this
+LL |     let _val = 'label: { (1, if other == 3 { break 'label (2, 3) } else { other }) };
+   |                        +                                                           +
 
-error: aborting due to 2 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/issue-97704.fixed b/src/test/ui/suggestions/issue-97704.fixed
new file mode 100644
index 00000000000..c42bdfff5f9
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97704.fixed
@@ -0,0 +1,19 @@
+// edition:2021
+// run-rustfix
+
+#![allow(unused)]
+
+use std::future::Future;
+
+async fn foo() -> Result<(), i32> {
+    func(async { Ok::<_, i32>(()) }).await?;
+    //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+
+    Ok(())
+}
+
+async fn func<T>(fut: impl Future<Output = T>) -> T {
+    fut.await
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-97704.rs b/src/test/ui/suggestions/issue-97704.rs
new file mode 100644
index 00000000000..5dfee6cac60
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97704.rs
@@ -0,0 +1,19 @@
+// edition:2021
+// run-rustfix
+
+#![allow(unused)]
+
+use std::future::Future;
+
+async fn foo() -> Result<(), i32> {
+    func(async { Ok::<_, i32>(()) })?;
+    //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+
+    Ok(())
+}
+
+async fn func<T>(fut: impl Future<Output = T>) -> T {
+    fut.await
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-97704.stderr b/src/test/ui/suggestions/issue-97704.stderr
new file mode 100644
index 00000000000..ca017be45ac
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97704.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/issue-97704.rs:9:5
+   |
+LL |     func(async { Ok::<_, i32>(()) })?;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), i32>>`
+   |
+   = help: the trait `Try` is not implemented for `impl Future<Output = Result<(), i32>>`
+help: consider `await`ing on the `Future`
+   |
+LL |     func(async { Ok::<_, i32>(()) }).await?;
+   |                                     ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.