about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-10-27 18:42:13 +0000
committerbors <bors@rust-lang.org>2021-10-27 18:42:13 +0000
commit4e0d3973fafdfb1c51011bc74e44257b5e3863f1 (patch)
tree6a7fe3cc445869485a6ce5f05c91cab291708bf0
parentdd757b9e0622815be615addb3031770922b87874 (diff)
parent623c3e144ef292f935e4d8603f7e512de6dc9d69 (diff)
downloadrust-4e0d3973fafdfb1c51011bc74e44257b5e3863f1.tar.gz
rust-4e0d3973fafdfb1c51011bc74e44257b5e3863f1.zip
Auto merge of #90347 - matthiaskrgr:rollup-rp2ms7j, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #90239 (Consistent big O notation in map.rs)
 - #90267 (fix: inner attribute followed by outer attribute causing ICE)
 - #90288 (Add hint for people missing `TryFrom`, `TryInto`, `FromIterator` import pre-2021)
 - #90304 (Add regression test for #75961)
 - #90344 (Add tracking issue number to const_cstr_unchecked)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs56
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs1
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs14
-rw-r--r--library/alloc/src/collections/btree/map.rs2
-rw-r--r--library/std/src/ffi/c_str.rs2
-rw-r--r--src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs13
-rw-r--r--src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs15
-rw-r--r--src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr18
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-shadow.stderr1
-rw-r--r--src/test/ui/suggestions/suggest-tryinto-edition-change.rs31
-rw-r--r--src/test/ui/suggestions/suggest-tryinto-edition-change.stderr76
-rw-r--r--src/test/ui/trait-bounds/issue-75961.rs7
13 files changed, 227 insertions, 15 deletions
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 5d994dbad4d..51cabb50cd3 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -221,12 +221,6 @@ impl AttrAnnotatedTokenStream {
                     for attr in &data.attrs {
                         match attr.style {
                             crate::AttrStyle::Outer => {
-                                assert!(
-                                    inner_attrs.len() == 0,
-                                    "Found outer attribute {:?} after inner attrs {:?}",
-                                    attr,
-                                    inner_attrs
-                                );
                                 outer_attrs.push(attr);
                             }
                             crate::AttrStyle::Inner => {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f94266c3aea..ccfab263bd4 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -66,6 +66,8 @@ crate struct ImportSuggestion {
     pub descr: &'static str,
     pub path: Path,
     pub accessible: bool,
+    /// An extra note that should be issued if this item is suggested
+    pub note: Option<String>,
 }
 
 /// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -872,11 +874,38 @@ impl<'a> Resolver<'a> {
                         }
 
                         if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+                            // See if we're recommending TryFrom, TryInto, or FromIterator and add
+                            // a note about editions
+                            let note = if let Some(did) = did {
+                                let requires_note = !did.is_local()
+                                    && this.cstore().item_attrs(did, this.session).iter().any(
+                                        |attr| {
+                                            if attr.has_name(sym::rustc_diagnostic_item) {
+                                                [sym::TryInto, sym::TryFrom, sym::FromIterator]
+                                                    .map(|x| Some(x))
+                                                    .contains(&attr.value_str())
+                                            } else {
+                                                false
+                                            }
+                                        },
+                                    );
+
+                                requires_note.then(|| {
+                                    format!(
+                                        "'{}' is included in the prelude starting in Edition 2021",
+                                        path_names_to_string(&path)
+                                    )
+                                })
+                            } else {
+                                None
+                            };
+
                             candidates.push(ImportSuggestion {
                                 did,
                                 descr: res.descr(),
                                 path,
                                 accessible: child_accessible,
+                                note,
                             });
                         }
                     }
@@ -1764,12 +1793,14 @@ crate fn show_candidates(
         return;
     }
 
-    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
-    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+        Vec::new();
+    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+        Vec::new();
 
     candidates.iter().for_each(|c| {
         (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
-            .push((path_names_to_string(&c.path), c.descr, c.did))
+            .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
     });
 
     // we want consistent results across executions, but candidates are produced
@@ -1792,6 +1823,10 @@ crate fn show_candidates(
         let instead = if instead { " instead" } else { "" };
         let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
 
+        for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+            err.note(note);
+        }
+
         if let Some(span) = use_placement_span {
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
@@ -1820,7 +1855,7 @@ crate fn show_candidates(
         assert!(!inaccessible_path_strings.is_empty());
 
         if inaccessible_path_strings.len() == 1 {
-            let (name, descr, def_id) = &inaccessible_path_strings[0];
+            let (name, descr, def_id, note) = &inaccessible_path_strings[0];
             let msg = format!("{} `{}` exists but is inaccessible", descr, name);
 
             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
@@ -1832,12 +1867,15 @@ crate fn show_candidates(
             } else {
                 err.note(&msg);
             }
+            if let Some(note) = (*note).as_deref() {
+                err.note(note);
+            }
         } else {
-            let (_, descr_first, _) = &inaccessible_path_strings[0];
+            let (_, descr_first, _, _) = &inaccessible_path_strings[0];
             let descr = if inaccessible_path_strings
                 .iter()
                 .skip(1)
-                .all(|(_, descr, _)| descr == descr_first)
+                .all(|(_, descr, _, _)| descr == descr_first)
             {
                 descr_first.to_string()
             } else {
@@ -1848,7 +1886,7 @@ crate fn show_candidates(
             let mut has_colon = false;
 
             let mut spans = Vec::new();
-            for (name, _, def_id) in &inaccessible_path_strings {
+            for (name, _, def_id, _) in &inaccessible_path_strings {
                 if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
                     let span = definitions.def_span(local_def_id);
                     let span = session.source_map().guess_head_span(span);
@@ -1868,6 +1906,10 @@ crate fn show_candidates(
                 multi_span.push_span_label(span, format!("`{}`: not accessible", name));
             }
 
+            for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+                err.note(note);
+            }
+
             err.span_note(multi_span, &msg);
         }
     }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1748a9be8e1..5f90fcdfa64 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1502,6 +1502,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                                 descr: "module",
                                 path,
                                 accessible: true,
+                                note: None,
                             },
                         ));
                     } else {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 183ebc559ae..28b19981c2d 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1203,6 +1203,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut candidates = valid_out_of_scope_traits;
             candidates.sort();
             candidates.dedup();
+
+            // `TryFrom` and `FromIterator` have no methods
+            let edition_fix = candidates
+                .iter()
+                .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+                .map(|&d| d);
+
             err.help("items from traits can only be used if the trait is in scope");
             let msg = format!(
                 "the following {traits_are} implemented but not in scope; \
@@ -1212,6 +1219,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
 
             self.suggest_use_candidates(err, msg, candidates);
+            if let Some(did) = edition_fix {
+                err.note(&format!(
+                    "'{}' is included in the prelude starting in Edition 2021",
+                    with_crate_prefix(|| self.tcx.def_path_str(did))
+                ));
+            }
+
             true
         } else {
             false
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 07920a6dba6..e1d5ec97678 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -55,7 +55,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 /// performance on *small* nodes of elements which are cheap to compare. However in the future we
 /// would like to further explore choosing the optimal search strategy based on the choice of B,
 /// and possibly other factors. Using linear search, searching for a random element is expected
-/// to take O(B * log(n)) comparisons, which is generally worse than a BST. In practice,
+/// to take B * log(n) comparisons, which is generally worse than a BST. In practice,
 /// however, performance is excellent.
 ///
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 3cb3f480de3..b7822b40a7c 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -1257,7 +1257,7 @@ impl CStr {
     #[inline]
     #[must_use]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
+    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
         // SAFETY: Casting to CStr is safe because its internal representation
         // is a [u8] too (safe only inside std).
diff --git a/src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs b/src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs
new file mode 100644
index 00000000000..e5604b816b5
--- /dev/null
+++ b/src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(ICE)]
+pub fn derive(_: TokenStream) -> TokenStream {
+    r#"#[allow(missing_docs)] struct X { }"#.parse().unwrap()
+}
diff --git a/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs
new file mode 100644
index 00000000000..fe67d9822fc
--- /dev/null
+++ b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs
@@ -0,0 +1,15 @@
+// aux-build:issue-89971-outer-attr-following-inner-attr-ice.rs
+
+#[macro_use]
+extern crate issue_89971_outer_attr_following_inner_attr_ice;
+
+fn main() {
+    Mew();
+    X {};
+}
+
+#![deny(missing_docs)]
+//~^ ERROR an inner attribute is not permitted in this context
+#[derive(ICE)]
+#[deny(missing_docs)]
+struct Mew();
diff --git a/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr
new file mode 100644
index 00000000000..34a6ab00d7b
--- /dev/null
+++ b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr
@@ -0,0 +1,18 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:11:1
+   |
+LL | #![deny(missing_docs)]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | struct Mew();
+   | ------------- the inner attribute doesn't annotate this struct
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the struct, change the attribute from inner to outer style
+   |
+LL - #![deny(missing_docs)]
+LL + #[deny(missing_docs)]
+   | 
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
index e4662b430dc..d945b4c94ca 100644
--- a/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
+++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
@@ -15,6 +15,7 @@ LL |     fn try_into(self) -> Result<T, Self::Error>;
    |        the method is available for `Rc<u8>` here
    |
    = help: items from traits can only be used if the trait is in scope
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
 help: consider wrapping the receiver expression with the appropriate type
    |
 LL |         let _: u32 = Box::new(3u8).try_into().unwrap();
diff --git a/src/test/ui/suggestions/suggest-tryinto-edition-change.rs b/src/test/ui/suggestions/suggest-tryinto-edition-change.rs
new file mode 100644
index 00000000000..f03b42bbe47
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-tryinto-edition-change.rs
@@ -0,0 +1,31 @@
+// Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions
+// Edition 2021 change
+// edition:2018
+
+fn test() {
+    let _i: i16 = 0_i32.try_into().unwrap();
+    //~^ ERROR no method named `try_into` found for type `i32` in the current scope
+    //~| NOTE method not found in `i32`
+    //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+
+    let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE not found in this scope
+    //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+
+    let _i: i16 = TryInto::try_into(0_i32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE not found in this scope
+    //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+
+    let _v: Vec<_> = FromIterator::from_iter(&[1]);
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/suggestions/suggest-tryinto-edition-change.stderr b/src/test/ui/suggestions/suggest-tryinto-edition-change.stderr
new file mode 100644
index 00000000000..86f48716b16
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-tryinto-edition-change.stderr
@@ -0,0 +1,76 @@
+error[E0433]: failed to resolve: use of undeclared type `TryFrom`
+  --> $DIR/suggest-tryinto-edition-change.rs:11:19
+   |
+LL |     let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+   |                   ^^^^^^^ not found in this scope
+   |
+   = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+   = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+   |
+LL | use core::convert::TryFrom;
+   |
+LL | use std::convert::TryFrom;
+   |
+
+error[E0433]: failed to resolve: use of undeclared type `TryInto`
+  --> $DIR/suggest-tryinto-edition-change.rs:17:19
+   |
+LL |     let _i: i16 = TryInto::try_into(0_i32).unwrap();
+   |                   ^^^^^^^ not found in this scope
+   |
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+   = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+   |
+LL | use core::convert::TryInto;
+   |
+LL | use std::convert::TryInto;
+   |
+
+error[E0433]: failed to resolve: use of undeclared type `FromIterator`
+  --> $DIR/suggest-tryinto-edition-change.rs:23:22
+   |
+LL |     let _v: Vec<_> = FromIterator::from_iter(&[1]);
+   |                      ^^^^^^^^^^^^
+   |
+  ::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | pub trait IntoIterator {
+   | ---------------------- similarly named trait `IntoIterator` defined here
+   |
+   = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+   = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+help: a trait with a similar name exists
+   |
+LL |     let _v: Vec<_> = IntoIterator::from_iter(&[1]);
+   |                      ~~~~~~~~~~~~
+help: consider importing one of these items
+   |
+LL | use core::iter::FromIterator;
+   |
+LL | use std::iter::FromIterator;
+   |
+
+error[E0599]: no method named `try_into` found for type `i32` in the current scope
+  --> $DIR/suggest-tryinto-edition-change.rs:6:25
+   |
+LL |     let _i: i16 = 0_i32.try_into().unwrap();
+   |                         ^^^^^^^^ method not found in `i32`
+   |
+  ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn try_into(self) -> Result<T, Self::Error>;
+   |        -------- the method is available for `i32` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use std::convert::TryInto;
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0433, E0599.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/src/test/ui/trait-bounds/issue-75961.rs b/src/test/ui/trait-bounds/issue-75961.rs
new file mode 100644
index 00000000000..367eac7182a
--- /dev/null
+++ b/src/test/ui/trait-bounds/issue-75961.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+    <&mut () as Clone>::clone(&s);
+}
+
+fn main() {}