From 839216a57c841c5cdd099cdecf8bd6dbf5808ae4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Jul 2020 14:12:31 +0200 Subject: [PATCH 01/17] Improve logo image display in different themes --- src/librustdoc/html/static/themes/ayu.css | 4 ++++ src/librustdoc/html/static/themes/dark.css | 4 ++++ src/librustdoc/html/static/themes/light.css | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 1326acec51ce..24c9472bd8c9 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -61,6 +61,10 @@ pre { background-color: #14191f; } +.logo-container > img { + filter: drop-shadow(0 0 5px #fff); +} + /* Improve the scrollbar display on firefox */ * { scrollbar-color: #5c6773 transparent; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index dc15220aa069..6c7fcd1df7b4 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -32,6 +32,10 @@ pre { background-color: #505050; } +.logo-container > img { + filter: drop-shadow(0 0 5px #fff); +} + /* Improve the scrollbar display on firefox */ * { scrollbar-color: rgb(64, 65, 67) #717171; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 64d59ca411a8..c1e5bad639bf 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -43,6 +43,10 @@ pre { scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; } +.logo-container > img { + filter: drop-shadow(0 0 5px #aaa); +} + /* Improve the scrollbar display on webkit-based browsers */ ::-webkit-scrollbar-track { background-color: #ecebeb; From c5cc29b0e0bb8238955691dc0cc324050653cbeb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 20 Jul 2020 10:11:53 -0400 Subject: [PATCH 02/17] Parse rustc_deprecated as deprecated attribute --- src/librustc_attr/builtin.rs | 96 ++++++++++--------- src/librustc_error_codes/error_codes.rs | 2 +- .../stability-attribute-sanity.rs | 2 +- .../stability-attribute-sanity.stderr | 4 +- 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 0606fac2fe74..16d776593ac5 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -124,7 +124,6 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op /// /// - `#[stable]` /// - `#[unstable]` -/// - `#[rustc_deprecated]` #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable_Generic)] pub struct Stability { @@ -213,7 +212,6 @@ where 'outer: for attr in attrs_iter { if ![ - sym::rustc_deprecated, sym::rustc_const_unstable, sym::rustc_const_stable, sym::unstable, @@ -299,35 +297,6 @@ where let meta_name = meta.name_or_empty(); match meta_name { - sym::rustc_deprecated => { - if rustc_depr.is_some() { - struct_span_err!( - diagnostic, - item_sp, - E0540, - "multiple rustc_deprecated attributes" - ) - .emit(); - continue 'outer; - } - - get_meta!(since, reason, suggestion); - - match (since, reason) { - (Some(since), Some(reason)) => { - rustc_depr = Some(RustcDeprecation { since, reason, suggestion }) - } - (None, _) => { - handle_errors(sess, attr.span, AttrError::MissingSince); - continue; - } - _ => { - struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'") - .emit(); - continue; - } - } - } sym::rustc_const_unstable | sym::unstable => { if meta_name == sym::unstable && stab.is_some() { handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels); @@ -714,7 +683,16 @@ pub fn eval_condition( #[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)] pub struct Deprecation { pub since: Option, + /// The note to issue a reason. pub note: Option, + /// A text snippet used to completely replace any use of the deprecated item in an expression. + /// + /// This is currently unstable. + pub suggestion: Option, + + /// Whether to treat the since attribute as being a Rust version identifier + /// (rather than an opaque string). + pub is_since_rustc_version: bool, } /// Finds the deprecation attribute. `None` if none exists. @@ -738,7 +716,7 @@ where let diagnostic = &sess.span_diagnostic; 'outer: for attr in attrs_iter { - if !attr.check_name(sym::deprecated) { + if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) { continue; } @@ -751,11 +729,12 @@ where Some(meta) => meta, None => continue, }; - depr = match &meta.kind { - MetaItemKind::Word => Some(Deprecation { since: None, note: None }), - MetaItemKind::NameValue(..) => { - meta.value_str().map(|note| Deprecation { since: None, note: Some(note) }) - } + let mut since = None; + let mut note = None; + let mut suggestion = None; + match &meta.kind { + MetaItemKind::Word => {} + MetaItemKind::NameValue(..) => note = meta.value_str(), MetaItemKind::List(list) => { let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { @@ -789,8 +768,6 @@ where } }; - let mut since = None; - let mut note = None; for meta in list { match meta { NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { @@ -799,18 +776,32 @@ where continue 'outer; } } - sym::note => { + sym::note if attr.check_name(sym::deprecated) => { + if !get(mi, &mut note) { + continue 'outer; + } + } + sym::reason if attr.check_name(sym::rustc_deprecated) => { if !get(mi, &mut note) { continue 'outer; } } + sym::suggestion if attr.check_name(sym::rustc_deprecated) => { + if !get(mi, &mut suggestion) { + continue 'outer; + } + } _ => { handle_errors( sess, meta.span(), AttrError::UnknownMetaItem( pprust::path_to_string(&mi.path), - &["since", "note"], + if attr.check_name(sym::deprecated) { + &["since", "note"] + } else { + &["since", "reason", "suggestion"] + }, ), ); continue 'outer; @@ -829,10 +820,29 @@ where } } } + } + } + + if suggestion.is_some() && attr.check_name(sym::deprecated) { + unreachable!("only allowed on rustc_deprecated") + } - Some(Deprecation { since, note }) + if attr.check_name(sym::rustc_deprecated) { + if since.is_none() { + handle_errors(sess, attr.span, AttrError::MissingSince); + continue; } - }; + + if note.is_none() { + struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit(); + continue; + } + } + + mark_used(&attr); + + let is_since_rustc_version = attr.check_name(sym::rustc_deprecated); + depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version }); } depr diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index bbbd8359f012..99f4fb5c12cc 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -588,7 +588,7 @@ E0770: include_str!("./error_codes/E0770.md"), E0521, // borrowed data escapes outside of closure E0523, // E0526, // shuffle indices are not constant - E0540, // multiple rustc_deprecated attributes +// E0540, // multiple rustc_deprecated attributes E0542, // missing 'since' E0543, // missing 'reason' E0544, // multiple stability levels diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index 5db924642e59..80d7ae6dc637 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -62,7 +62,7 @@ fn multiple3() { } #[rustc_deprecated(since = "b", reason = "text")] #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels -pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540] +pub const fn multiple4() { } //~ ERROR multiple deprecated attributes //~^ ERROR Invalid stability or deprecation version found #[rustc_deprecated(since = "a", reason = "text")] diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 3c5da3f14403..134c657c6201 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -82,7 +82,7 @@ error[E0544]: multiple stability levels LL | #[stable(feature = "a", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0540]: multiple rustc_deprecated attributes +error[E0550]: multiple deprecated attributes --> $DIR/stability-attribute-sanity.rs:65:1 | LL | pub const fn multiple4() { } @@ -108,5 +108,5 @@ LL | fn deprecated_without_unstable_or_stable() { } error: aborting due to 18 previous errors -Some errors have detailed explanations: E0539, E0541. +Some errors have detailed explanations: E0539, E0541, E0550. For more information about an error, try `rustc --explain E0539`. From 21a3d294dc096422ebdd492d06d4e4ba4998d8a2 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 20 Jul 2020 10:12:21 -0400 Subject: [PATCH 03/17] rustc_depr no longer needs to be connected to stability We can deprecate non-stable/unstable items. --- src/librustc_attr/builtin.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 16d776593ac5..60ceb3e5df97 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -495,22 +495,6 @@ where } } - // Merge the deprecation info into the stability info - if let Some(rustc_depr) = rustc_depr { - if let Some(ref mut stab) = stab { - stab.rustc_depr = Some(rustc_depr); - } else { - struct_span_err!( - diagnostic, - item_sp, - E0549, - "rustc_deprecated attribute must be paired with \ - either stable or unstable attribute" - ) - .emit(); - } - } - // Merge the const-unstable info into the stability info if promotable || allow_const_fn_ptr { if let Some(ref mut stab) = const_stab { From 8454ee89b2f519a5436a4699c7f65b76ee4fb259 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 20 Jul 2020 10:44:43 -0400 Subject: [PATCH 04/17] Migrate rustc_depr uses to use deprecation attribute This should not be a change in behavior. --- src/librustc_attr/builtin.rs | 54 +--------- src/librustc_middle/middle/stability.rs | 71 +++++++------ src/librustc_passes/stability.rs | 128 ++++++++++++++---------- src/librustc_resolve/macros.rs | 19 ++-- src/librustdoc/clean/mod.rs | 5 +- src/librustdoc/clean/types.rs | 13 +-- src/librustdoc/html/render.rs | 29 ++---- 7 files changed, 138 insertions(+), 181 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 60ceb3e5df97..1e088b52dcc3 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -129,7 +129,6 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, - pub rustc_depr: Option, } /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. @@ -162,15 +161,6 @@ impl StabilityLevel { } } -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub struct RustcDeprecation { - pub since: Symbol, - pub reason: Symbol, - /// A text snippet used to completely replace any use of the deprecated item in an expression. - pub suggestion: Option, -} - /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`. /// This will not perform any "sanity checks" on the form of the attributes. pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool { @@ -204,7 +194,6 @@ where use StabilityLevel::*; let mut stab: Option = None; - let mut rustc_depr: Option = None; let mut const_stab: Option = None; let mut promotable = false; let mut allow_const_fn_ptr = false; @@ -256,45 +245,6 @@ where } }; - macro_rules! get_meta { - ($($name:ident),+) => { - $( - let mut $name = None; - )+ - for meta in metas { - if let Some(mi) = meta.meta_item() { - match mi.name_or_empty() { - $( - sym::$name => if !get(mi, &mut $name) { continue 'outer }, - )+ - _ => { - let expected = &[ $( stringify!($name) ),+ ]; - handle_errors( - sess, - mi.span, - AttrError::UnknownMetaItem( - pprust::path_to_string(&mi.path), - expected, - ), - ); - continue 'outer - } - } - } else { - handle_errors( - sess, - meta.span(), - AttrError::UnsupportedLiteral( - "unsupported literal", - false, - ), - ); - continue 'outer - } - } - } - } - let meta_name = meta.name_or_empty(); match meta_name { sym::rustc_const_unstable | sym::unstable => { @@ -398,7 +348,7 @@ where (Some(feature), reason, Some(_)) => { let level = Unstable { reason, issue: issue_num, is_soft }; if sym::unstable == meta_name { - stab = Some(Stability { level, feature, rustc_depr: None }); + stab = Some(Stability { level, feature }); } else { const_stab = Some(ConstStability { level, @@ -470,7 +420,7 @@ where (Some(feature), Some(since)) => { let level = Stable { since }; if sym::stable == meta_name { - stab = Some(Stability { level, feature, rustc_depr: None }); + stab = Some(Stability { level, feature }); } else { const_stab = Some(ConstStability { level, diff --git a/src/librustc_middle/middle/stability.rs b/src/librustc_middle/middle/stability.rs index 54c05bca3bd2..5f7ff54fd31c 100644 --- a/src/librustc_middle/middle/stability.rs +++ b/src/librustc_middle/middle/stability.rs @@ -5,7 +5,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, TyCtxt}; use rustc_ast::ast::CRATE_NODE_ID; -use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability}; +use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_feature::GateIssue; @@ -130,14 +130,26 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). -pub fn deprecation_in_effect(since: &str) -> bool { +pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { + let since = if let Some(since) = since { + if is_since_rustc_version { + since + } else { + // We assume that the deprecation is in effect if it's not a + // rustc version. + return true; + } + } else { + // If since attribute is not set, then we're definitely in effect. + return true; + }; fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() } if let Some(rustc) = option_env!("CFG_RELEASE") { - let since: Vec = parse_version(since); + let since: Vec = parse_version(&since); let rustc: Vec = parse_version(rustc); // We simply treat invalid `since` attributes as relating to a previous // Rust version, thus always displaying the warning. @@ -167,31 +179,27 @@ pub fn deprecation_suggestion( } } -fn deprecation_message_common(message: String, reason: Option) -> String { - match reason { - Some(reason) => format!("{}: {}", message, reason), - None => message, - } -} - pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) { - let message = format!("use of deprecated item '{}'", path); - (deprecation_message_common(message, depr.note), DEPRECATED) -} - -pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) { - let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) { + let (message, lint) = if deprecation_in_effect( + depr.is_since_rustc_version, + depr.since.map(Symbol::as_str).as_deref(), + ) { (format!("use of deprecated item '{}'", path), DEPRECATED) } else { ( format!( "use of item '{}' that will be deprecated in future version {}", - path, depr.since + path, + depr.since.unwrap() ), DEPRECATED_IN_FUTURE, ) }; - (deprecation_message_common(message, Some(depr.reason)), lint) + let message = match depr.note { + Some(reason) => format!("{}: {}", message, reason), + None => message, + }; + (message, lint) } pub fn early_report_deprecation( @@ -289,10 +297,23 @@ impl<'tcx> TyCtxt<'tcx> { .lookup_deprecation_entry(parent_def_id.to_def_id()) .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry)); - if !skip { + // #[deprecated] doesn't emit a notice if we're not on the + // topmost deprecation. For example, if a struct is deprecated, + // the use of a field won't be linted. + // + // #[rustc_deprecated] however wants to emit down the whole + // hierarchy. + if !skip || depr_entry.attr.is_since_rustc_version { let (message, lint) = deprecation_message(&depr_entry.attr, &self.def_path_str(def_id)); - late_report_deprecation(self, &message, None, lint, span, id); + late_report_deprecation( + self, + &message, + depr_entry.attr.suggestion, + lint, + span, + id, + ); } }; } @@ -310,16 +331,6 @@ impl<'tcx> TyCtxt<'tcx> { def_id, span, stability ); - if let Some(id) = id { - if let Some(stability) = stability { - if let Some(depr) = &stability.rustc_depr { - let (message, lint) = - rustc_deprecation_message(depr, &self.def_path_str(def_id)); - late_report_deprecation(self, &message, depr.suggestion, lint, span, id); - } - } - } - // Only the cross-crate scenario matters when checking unstable APIs let cross_crate = !def_id.is_local(); if !cross_crate { diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 5d972c70d139..830af8d31e7a 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -59,20 +59,50 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { ) where F: FnOnce(&mut Self), { + debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); + let mut did_error = false; if !self.tcx.features().staged_api { - self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children); - return; + did_error = self.forbid_staged_api_attrs(hir_id, attrs); } - // This crate explicitly wants staged API. + let depr = if did_error { + None + } else { + attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) + }; + let mut is_deprecated = false; + if let Some(depr) = &depr { + is_deprecated = true; - debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); - if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) { - self.tcx.sess.span_err( - item_sp, - "`#[deprecated]` cannot be used in staged API; \ - use `#[rustc_deprecated]` instead", + if kind == AnnotationKind::Prohibited { + self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless"); + } + + // `Deprecation` is just two pointers, no need to intern it + let depr_entry = DeprecationEntry::local(depr.clone(), hir_id); + self.index.depr_map.insert(hir_id, depr_entry); + } else if let Some(parent_depr) = self.parent_depr.clone() { + is_deprecated = true; + info!("tagging child {:?} as deprecated from parent", hir_id); + self.index.depr_map.insert(hir_id, parent_depr); + } + + if self.tcx.features().staged_api { + if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) { + self.tcx.sess.span_err( + item_sp, + "`#[deprecated]` cannot be used in staged API; \ + use `#[rustc_deprecated]` instead", + ); + } + } else { + self.recurse_with_stability_attrs( + depr.map(|d| DeprecationEntry::local(d, hir_id)), + None, + None, + visit_children, ); + return; } let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp); @@ -92,33 +122,34 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - let stab = stab.map(|mut stab| { + if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) { + if stab.is_none() { + struct_span_err!( + self.tcx.sess, + item_sp, + E0549, + "rustc_deprecated attribute must be paired with \ + either stable or unstable attribute" + ) + .emit(); + } + } + + let stab = stab.map(|stab| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container - && stab.level.is_stable() - && stab.rustc_depr.is_none()) + || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) { self.tcx.sess.span_err(item_sp, "This stability annotation is useless"); } debug!("annotate: found {:?}", stab); - // If parent is deprecated and we're not, inherit this by merging - // deprecated_since and its reason. - if let Some(parent_stab) = self.parent_stab { - if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() { - stab.rustc_depr = parent_stab.rustc_depr - } - } - let stab = self.tcx.intern_stability(stab); // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - if let ( - &Some(attr::RustcDeprecation { since: dep_since, .. }), - &attr::Stable { since: stab_since }, - ) = (&stab.rustc_depr, &stab.level) + if let (&Some(dep_since), &attr::Stable { since: stab_since }) = + (&depr.as_ref().and_then(|d| d.since), &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in @@ -163,19 +194,29 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs(stab, const_stab, visit_children); + self.recurse_with_stability_attrs( + depr.map(|d| DeprecationEntry::local(d, hir_id)), + stab, + const_stab, + visit_children, + ); } fn recurse_with_stability_attrs( &mut self, + depr: Option, stab: Option<&'tcx Stability>, const_stab: Option<&'tcx ConstStability>, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. + let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; + if let Some(depr) = depr { + replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); + } if let Some(stab) = stab { replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); } @@ -186,6 +227,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); + if let Some(orig_parent_depr) = replaced_parent_depr { + self.parent_depr = orig_parent_depr; + } if let Some(orig_parent_stab) = replaced_parent_stab { self.parent_stab = orig_parent_stab; } @@ -194,14 +238,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - fn forbid_staged_api_attrs( - &mut self, - hir_id: HirId, - attrs: &[Attribute], - item_sp: Span, - kind: AnnotationKind, - visit_children: impl FnOnce(&mut Self), - ) { + // returns true if an error occurred, used to suppress some spurious errors + fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, @@ -210,6 +248,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { sym::rustc_const_unstable, sym::rustc_const_stable, ]; + let mut has_error = false; for attr in attrs { let name = attr.name_or_empty(); if unstable_attrs.contains(&name) { @@ -221,6 +260,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { "stability attributes may not be used outside of the standard library", ) .emit(); + has_error = true; } } @@ -232,24 +272,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) { - if kind == AnnotationKind::Prohibited { - self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless"); - } - - // `Deprecation` is just two pointers, no need to intern it - let depr_entry = DeprecationEntry::local(depr, hir_id); - self.index.depr_map.insert(hir_id, depr_entry.clone()); - - let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry)); - visit_children(self); - self.parent_depr = orig_parent_depr; - } else if let Some(parent_depr) = self.parent_depr.clone() { - self.index.depr_map.insert(hir_id, parent_depr); - visit_children(self); - } else { - visit_children(self); - } + has_error } } @@ -454,7 +477,6 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { is_soft: false, }, feature: sym::rustc_private, - rustc_depr: None, }); annotator.parent_stab = Some(stability); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3976e501c169..fee7cb4836e3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1017,22 +1017,17 @@ impl<'a> Resolver<'a> { ); } } - if let Some(depr) = &stability.rustc_depr { - let path = pprust::path_to_string(path); - let (message, lint) = stability::rustc_deprecation_message(depr, &path); - stability::early_report_deprecation( - &mut self.lint_buffer, - &message, - depr.suggestion, - lint, - span, - ); - } } if let Some(depr) = &ext.deprecation { let path = pprust::path_to_string(&path); let (message, lint) = stability::deprecation_message(depr, &path); - stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span); + stability::early_report_deprecation( + &mut self.lint_buffer, + &message, + depr.suggestion, + lint, + span, + ); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8a4ee91df405..94d95115dcdb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2353,10 +2353,6 @@ impl Clean for attr::Stability { attr::Stable { ref since } => since.to_string(), _ => String::new(), }, - deprecation: self.rustc_depr.as_ref().map(|d| Deprecation { - note: Some(d.reason.to_string()).filter(|r| !r.is_empty()), - since: Some(d.since.to_string()).filter(|d| !d.is_empty()), - }), unstable_reason: match self.level { attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()), _ => None, @@ -2374,6 +2370,7 @@ impl Clean for attr::Deprecation { Deprecation { since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()), note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()), + is_since_rustc_version: self.is_since_rustc_version, } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6a03722cd080..071834c59d65 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -195,7 +195,8 @@ impl Item { classes.push("unstable"); } - if s.deprecation.is_some() { + // FIXME: what about non-staged API items that are deprecated? + if self.deprecation.is_some() { classes.push("deprecated"); } @@ -216,14 +217,6 @@ impl Item { ItemType::from(self) } - /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes. - /// - /// If the item is not deprecated, returns `None`. - pub fn deprecation(&self) -> Option<&Deprecation> { - self.deprecation - .as_ref() - .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) - } pub fn is_default(&self) -> bool { match self.inner { ItemEnum::MethodItem(ref meth) => { @@ -1528,7 +1521,6 @@ pub struct Stability { pub level: stability::StabilityLevel, pub feature: Option, pub since: String, - pub deprecation: Option, pub unstable_reason: Option, pub issue: Option, } @@ -1537,6 +1529,7 @@ pub struct Stability { pub struct Deprecation { pub since: Option, pub note: Option, + pub is_since_rustc_version: bool, } /// An type binding on an associated type (e.g., `A = Bar` in `Foo` or diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f872ed7010c7..f7050cf37772 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2216,16 +2216,10 @@ fn stability_tags(item: &clean::Item) -> String { } // The trailing space after each tag is to space it properly against the rest of the docs. - if item.deprecation().is_some() { + if let Some(depr) = &item.deprecation { let mut message = "Deprecated"; - if let Some(ref stab) = item.stability { - if let Some(ref depr) = stab.deprecation { - if let Some(ref since) = depr.since { - if !stability::deprecation_in_effect(&since) { - message = "Deprecation planned"; - } - } - } + if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) { + message = "Deprecation planned"; } tags += &tag_html("deprecated", message); } @@ -2254,23 +2248,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { let mut stability = vec![]; let error_codes = cx.shared.codes; - if let Some(Deprecation { note, since }) = &item.deprecation() { + if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] // but only display the future-deprecation messages for #[rustc_deprecated]. let mut message = if let Some(since) = since { - format!("Deprecated since {}", Escape(since)) + if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { + format!("Deprecating in {}", Escape(&since)) + } else { + format!("Deprecated since {}", Escape(&since)) + } } else { String::from("Deprecated") }; - if let Some(ref stab) = item.stability { - if let Some(ref depr) = stab.deprecation { - if let Some(ref since) = depr.since { - if !stability::deprecation_in_effect(&since) { - message = format!("Deprecating in {}", Escape(&since)); - } - } - } - } if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); From 6a9c5fb4cc499bc828422e32689c8f098542f821 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 22 Jul 2020 12:50:26 +0200 Subject: [PATCH 05/17] polymorphize GlobalAlloc::Function --- src/librustc_codegen_llvm/common.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 1 + src/test/ui/polymorphization/promoted-function.rs | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/polymorphization/promoted-function.rs diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 0e1cd8e493d9..2a50d4a46d27 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -257,7 +257,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { (value, AddressSpace::DATA) } GlobalAlloc::Function(fn_instance) => ( - self.get_fn_addr(fn_instance), + self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), GlobalAlloc::Static(def_id) => { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 0b5f27fc17a7..30d25270f03e 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1197,6 +1197,7 @@ fn collect_miri<'tcx>( } } GlobalAlloc::Function(fn_instance) => { + let fn_instance = fn_instance.polymorphize(tcx); if should_codegen_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); diff --git a/src/test/ui/polymorphization/promoted-function.rs b/src/test/ui/polymorphization/promoted-function.rs new file mode 100644 index 000000000000..0d3af7a89c2a --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function.rs @@ -0,0 +1,13 @@ +// run-pass +fn fop() {} + +fn bar() -> &'static fn() { + &(fop:: as fn()) +} +pub const FN: &'static fn() = &(fop:: as fn()); + +fn main() { + bar::(); + bar::(); + (FN)(); +} From 40b6bccd6431e5d3032279ec5f6d269cacc7fe9b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 22 Jul 2020 13:01:55 +0200 Subject: [PATCH 06/17] no need to polymorphize --- src/librustc_mir/monomorphize/collector.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 30d25270f03e..0b5f27fc17a7 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1197,7 +1197,6 @@ fn collect_miri<'tcx>( } } GlobalAlloc::Function(fn_instance) => { - let fn_instance = fn_instance.polymorphize(tcx); if should_codegen_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); From 2152d18f9248d376fd43a6192888664f33dfb08d Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 14 Jul 2020 11:32:50 +0200 Subject: [PATCH 07/17] More BTreeMap test cases, some exposing undefined behaviour --- src/liballoc/tests/btree/map.rs | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f66b5814ca0d..5cd3ce0a2d80 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt::Debug; use std::iter::FromIterator; +use std::mem; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -25,6 +26,20 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1; // It's not the minimum size: removing an element from such a tree does not always reduce height. const MIN_INSERTS_HEIGHT_2: usize = NODE_CAPACITY + (NODE_CAPACITY + 1) * NODE_CAPACITY + 1; +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + mem::swap(dummy, r); + } + for r in refs { + mem::swap(dummy, r); + } +} + #[test] fn test_basic_large() { let mut map = BTreeMap::new(); @@ -268,7 +283,14 @@ fn test_iter_mut_mutation() { } #[test] +#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_values_mut() { + let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect(); + test_all_refs(&mut 13, a.values_mut()); +} + +#[test] +fn test_values_mut_mutation() { let mut a = BTreeMap::new(); a.insert(1, String::from("hello")); a.insert(2, String::from("goodbye")); @@ -281,6 +303,36 @@ fn test_values_mut() { assert_eq!(values, [String::from("hello!"), String::from("goodbye!")]); } +#[test] +#[cfg_attr(miri, ignore)] // FIXME: fails in Miri +fn test_iter_entering_root_twice() { + let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect(); + let mut it = map.iter_mut(); + let front = it.next().unwrap(); + let back = it.next_back().unwrap(); + assert_eq!(front, (&0, &mut 0)); + assert_eq!(back, (&1, &mut 1)); + *front.1 = 24; + *back.1 = 42; + assert_eq!(front, (&0, &mut 24)); + assert_eq!(back, (&1, &mut 42)); +} + +#[test] +#[cfg_attr(miri, ignore)] // FIXME: fails in Miri +fn test_iter_descending_to_same_node_twice() { + let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect(); + let mut it = map.iter_mut(); + // Descend into first child. + let front = it.next().unwrap(); + // Descend into first child again, after running through second child. + while it.next_back().is_some() {} + // Check immutable access. + assert_eq!(front, (&0, &mut 0)); + // Perform mutable access. + *front.1 = 42; +} + #[test] fn test_iter_mixed() { // Miri is too slow @@ -1283,6 +1335,34 @@ fn test_split_off_empty_left() { assert!(right.into_iter().eq(data)); } +// In a tree with 3 levels, if all but a part of the first leaf node is split off, +// make sure fix_top eliminates both top levels. +#[test] +fn test_split_off_tiny_left_height_2() { + let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); + let mut left: BTreeMap<_, _> = pairs.clone().collect(); + let right = left.split_off(&1); + assert_eq!(left.len(), 1); + assert_eq!(right.len(), MIN_INSERTS_HEIGHT_2 - 1); + assert_eq!(*left.first_key_value().unwrap().0, 0); + assert_eq!(*right.first_key_value().unwrap().0, 1); +} + +// In a tree with 3 levels, if only part of the last leaf node is split off, +// make sure fix_top eliminates both top levels. +#[test] +fn test_split_off_tiny_right_height_2() { + let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); + let last = MIN_INSERTS_HEIGHT_2 - 1; + let mut left: BTreeMap<_, _> = pairs.clone().collect(); + assert_eq!(*left.last_key_value().unwrap().0, last); + let right = left.split_off(&last); + assert_eq!(left.len(), MIN_INSERTS_HEIGHT_2 - 1); + assert_eq!(right.len(), 1); + assert_eq!(*left.last_key_value().unwrap().0, last - 1); + assert_eq!(*right.last_key_value().unwrap().0, last); +} + #[test] fn test_split_off_large_random_sorted() { // Miri is too slow From dc7d1156bef37b2fe38c3b5c83919dd8f0e39414 Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Wed, 22 Jul 2020 22:54:06 -0700 Subject: [PATCH 08/17] Don't ICE on unconstrained anonymous lifetimes inside associated types. --- src/librustc_typeck/astconv.rs | 29 +++++++++++-------- src/test/ui/associated-types/issue-62200.rs | 14 +++++++++ .../ui/associated-types/issue-62200.stderr | 11 +++++++ 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/associated-types/issue-62200.rs create mode 100644 src/test/ui/associated-types/issue-62200.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 37f48f82ea67..e6d59d30e2f5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1485,28 +1485,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("late_bound_in_ty = {:?}", late_bound_in_ty); for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { let br_name = match *br { - ty::BrNamed(_, name) => name, - _ => { - span_bug!( - binding.span, - "anonymous bound region {:?} in binding but not trait ref", - br - ); - } + ty::BrNamed(_, name) => format!("lifetime `{}`", name), + _ => "an anonymous lifetime".to_string(), }; // FIXME: point at the type params that don't have appropriate lifetimes: // struct S1 Fn(&i32, &i32) -> &'a i32>(F); // ---- ---- ^^^^^^^ - struct_span_err!( + let mut err = struct_span_err!( tcx.sess, binding.span, E0582, - "binding for associated type `{}` references lifetime `{}`, \ + "binding for associated type `{}` references {}, \ which does not appear in the trait input types", binding.item_name, br_name - ) - .emit(); + ); + + if let ty::BrAnon(_) = *br { + // The only way for an anonymous lifetime to wind up + // in the return type but **also** be unconstrained is + // if it only appears in "associated types" in the + // input. See #62200 for an example. In this case, + // though we can easily give a hint that ought to be + // relevant. + err.note("lifetimes appearing in an associated type are not considered constrained"); + } + + err.emit(); } } } diff --git a/src/test/ui/associated-types/issue-62200.rs b/src/test/ui/associated-types/issue-62200.rs new file mode 100644 index 000000000000..10f06eb26f8d --- /dev/null +++ b/src/test/ui/associated-types/issue-62200.rs @@ -0,0 +1,14 @@ +struct S {} + +trait T<'a> { + type A; +} + +impl T<'_> for S { + type A = u32; +} + +fn foo(x: impl Fn(>::A) -> >::A) {} +//~^ ERROR binding for associated type `Output` references an anonymous lifetime + +fn main() {} diff --git a/src/test/ui/associated-types/issue-62200.stderr b/src/test/ui/associated-types/issue-62200.stderr new file mode 100644 index 000000000000..f14cd81fdfe1 --- /dev/null +++ b/src/test/ui/associated-types/issue-62200.stderr @@ -0,0 +1,11 @@ +error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types + --> $DIR/issue-62200.rs:11:39 + | +LL | fn foo(x: impl Fn(>::A) -> >::A) {} + | ^^^^^^^^^^^^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0582`. From bbaab63f844d64ca726a2a83c18774b3957c7169 Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Wed, 22 Jul 2020 23:19:38 -0700 Subject: [PATCH 09/17] Include the note in the test. --- src/test/ui/associated-types/issue-62200.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/associated-types/issue-62200.rs b/src/test/ui/associated-types/issue-62200.rs index 10f06eb26f8d..9d18690e9604 100644 --- a/src/test/ui/associated-types/issue-62200.rs +++ b/src/test/ui/associated-types/issue-62200.rs @@ -10,5 +10,6 @@ impl T<'_> for S { fn foo(x: impl Fn(>::A) -> >::A) {} //~^ ERROR binding for associated type `Output` references an anonymous lifetime +//~^^ NOTE lifetimes appearing in an associated type are not considered constrained fn main() {} From 37f6f7f4af8e726d33fb15c25e673984bb94172b Mon Sep 17 00:00:00 2001 From: kanimum Date: Thu, 23 Jul 2020 17:29:52 +0900 Subject: [PATCH 10/17] Fix typo --- src/libcore/iter/range.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 9f55f378a5cc..9f34aee1947c 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -32,7 +32,7 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// * `steps_between(&a, &b) == Some(n)` only if `a <= b` /// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b` /// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; - /// this is the case wheen it would require more than `usize::MAX` steps to get to `b` + /// this is the case when it would require more than `usize::MAX` steps to get to `b` /// * `steps_between(&a, &b) == None` if `a > b` fn steps_between(start: &Self, end: &Self) -> Option; From 3f4f3134d955c6be8a1bb0b1f875990ae642f5c1 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 23 Jul 2020 21:52:48 +0900 Subject: [PATCH 11/17] Add missing backticks in diagnostics note --- src/libcore/ops/function.rs | 6 +++--- src/test/ui/closure-expected.stderr | 2 +- src/test/ui/extern/extern-wrong-value-type.stderr | 2 +- .../issue-68642-broken-llvm-ir.stderr | 2 +- .../issue-68643-broken-mir.stderr | 2 +- .../issue-68644-codegen-selection.stderr | 2 +- .../issue-68645-codegen-fulfillment.stderr | 2 +- src/test/ui/issues/issue-22034.stderr | 2 +- .../rfcs/rfc-2396-target_feature-11/fn-traits.stderr | 12 ++++++------ 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index 22a738d0bc1c..4f08aa451875 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -59,7 +59,7 @@ #[rustc_on_unimplemented( on( Args = "()", - note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}" + note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), message = "expected a `{Fn}<{Args}>` closure, found `{Self}`", label = "expected an `Fn<{Args}>` closure, found `{Self}`" @@ -141,7 +141,7 @@ pub trait Fn: FnMut { #[rustc_on_unimplemented( on( Args = "()", - note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}" + note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`", label = "expected an `FnMut<{Args}>` closure, found `{Self}`" @@ -215,7 +215,7 @@ pub trait FnMut: FnOnce { #[rustc_on_unimplemented( on( Args = "()", - note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}" + note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`", label = "expected an `FnOnce<{Args}>` closure, found `{Self}`" diff --git a/src/test/ui/closure-expected.stderr b/src/test/ui/closure-expected.stderr index ae4f4d69b5ef..687dd97ca6ce 100644 --- a/src/test/ui/closure-expected.stderr +++ b/src/test/ui/closure-expected.stderr @@ -5,7 +5,7 @@ LL | let y = x.or_else(4); | ^ expected an `FnOnce<()>` closure, found `{integer}` | = help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}` - = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` error: aborting due to previous error diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index 64f01b47792c..2cb15f84f697 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -8,7 +8,7 @@ LL | is_fn(f); | ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` | = help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}` - = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 2fab7ffb6605..2fe266b8018e 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | LL | impl> Fun for T { diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index 186e142138be..e335523778b4 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | LL | impl> Fun for T { diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index d16bdcbbb6b0..d7a5bb0ebe54 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | LL | impl> Fun for T { diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 72c42917c83c..0670625aa2f1 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | LL | impl> Fun for T { diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index 19fb080154a4..132880aab11e 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -5,7 +5,7 @@ LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn<()>` closure, found `()` | = help: the trait `std::ops::Fn<()>` is not implemented for `()` - = note: wrap the `()` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` = note: required for the cast to the object type `dyn std::ops::Fn()` error: aborting due to previous error diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 448077b439e8..f9b4eed0497c 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -8,7 +8,7 @@ LL | call(foo); | ^^^ expected an `Fn<()>` closure, found `fn() {foo}` | = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` @@ -21,7 +21,7 @@ LL | call_mut(foo); | ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` | = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` @@ -34,7 +34,7 @@ LL | call_once(foo); | ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` | = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` @@ -47,7 +47,7 @@ LL | call(foo_unsafe); | ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` | = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` - = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` @@ -60,7 +60,7 @@ LL | call_mut(foo_unsafe); | ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` | = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` - = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` @@ -73,7 +73,7 @@ LL | call_once(foo_unsafe); | ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` | = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` - = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits error: aborting due to 6 previous errors From facc46fd0a85408bc05aa19b80131e3cfb5fe3dd Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 22 Jul 2020 22:37:54 +0200 Subject: [PATCH 12/17] BTreeMap::drain_filter: replace needless unsafety and test --- src/liballoc/collections/btree/map.rs | 9 +---- src/liballoc/tests/btree/map.rs | 58 +++++++++++++++++++++------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index bf5748739d47..09b24fde7469 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1681,19 +1681,12 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { edge.reborrow().next_kv().ok().map(|kv| kv.into_kv()) } - unsafe fn next_kv( - &mut self, - ) -> Option, K, V, marker::LeafOrInternal>, marker::KV>> { - let edge = self.cur_leaf_edge.as_ref()?; - unsafe { ptr::read(edge).next_kv().ok() } - } - /// Implementation of a typical `DrainFilter::next` method, given the predicate. pub(super) fn next(&mut self, pred: &mut F) -> Option<(K, V)> where F: FnMut(&K, &mut V) -> bool, { - while let Some(mut kv) = unsafe { self.next_kv() } { + while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() { let (k, v) = kv.kv_mut(); if pred(k, v) { *self.length -= 1; diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f66b5814ca0d..295c62625712 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -835,10 +835,8 @@ mod test_drain_filter { } } - let mut map = BTreeMap::new(); - map.insert(0, D); - map.insert(4, D); - map.insert(8, D); + // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. + let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); catch_unwind(move || { drop(map.drain_filter(|i, _| { @@ -846,7 +844,7 @@ mod test_drain_filter { true })) }) - .ok(); + .unwrap_err(); assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); assert_eq!(DROPS.load(Ordering::SeqCst), 3); @@ -864,10 +862,8 @@ mod test_drain_filter { } } - let mut map = BTreeMap::new(); - map.insert(0, D); - map.insert(4, D); - map.insert(8, D); + // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. + let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); catch_unwind(AssertUnwindSafe(|| { drop(map.drain_filter(|i, _| { @@ -878,7 +874,45 @@ mod test_drain_filter { } })) })) - .ok(); + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + assert_eq!(map.first_entry().unwrap().key(), &4); + assert_eq!(map.last_entry().unwrap().key(), &8); + } + + // Same as above, but attempt to use the iterator again after the panic in the predicate + #[test] + fn pred_panic_reuse() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. + let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); + + { + let mut it = map.drain_filter(|i, _| { + PREDS.fetch_add(1usize << i, Ordering::SeqCst); + match i { + 0 => true, + _ => panic!(), + } + }); + catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); + // Iterator behaviour after a panic is explicitly unspecified, + // so this is just the current implementation: + let result = catch_unwind(AssertUnwindSafe(|| it.next())); + assert!(matches!(result, Ok(None))); + } assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); assert_eq!(DROPS.load(Ordering::SeqCst), 1); @@ -1319,7 +1353,7 @@ fn test_into_iter_drop_leak_height_0() { map.insert("d", D); map.insert("e", D); - catch_unwind(move || drop(map.into_iter())).ok(); + catch_unwind(move || drop(map.into_iter())).unwrap_err(); assert_eq!(DROPS.load(Ordering::SeqCst), 5); } @@ -1343,7 +1377,7 @@ fn test_into_iter_drop_leak_height_1() { DROPS.store(0, Ordering::SeqCst); PANIC_POINT.store(panic_point, Ordering::SeqCst); let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect(); - catch_unwind(move || drop(map.into_iter())).ok(); + catch_unwind(move || drop(map.into_iter())).unwrap_err(); assert_eq!(DROPS.load(Ordering::SeqCst), size); } } From 9be9d728e9f61d05e7659b2f9facae57fb913111 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Jul 2020 21:11:40 +0200 Subject: [PATCH 13/17] Clean up E0727 explanation --- src/librustc_error_codes/error_codes/E0727.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0727.md b/src/librustc_error_codes/error_codes/E0727.md index be1b68e645d0..386daea0c57e 100644 --- a/src/librustc_error_codes/error_codes/E0727.md +++ b/src/librustc_error_codes/error_codes/E0727.md @@ -1,6 +1,6 @@ A `yield` clause was used in an `async` context. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0727,edition2018 #![feature(generators)] From d6b50d8230629acd0aa7837942c7da112274848e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Jul 2020 21:08:21 +0200 Subject: [PATCH 14/17] Clean up E0724 explanation --- src/librustc_error_codes/error_codes/E0724.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0724.md b/src/librustc_error_codes/error_codes/E0724.md index 7a7ba1548543..e8f84d0fc7d5 100644 --- a/src/librustc_error_codes/error_codes/E0724.md +++ b/src/librustc_error_codes/error_codes/E0724.md @@ -1,4 +1,5 @@ -`#[ffi_returns_twice]` was used on non-foreign function. +`#[ffi_returns_twice]` was used on something other than a foreign function +declaration. Erroneous code example: From 62e75a1f221947b4f5f8adba5992b68e6a0d3f42 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 23 Jul 2020 17:41:05 -0700 Subject: [PATCH 15/17] Fix ICE while building MIR with type errors Fixes #74047. --- src/librustc_mir_build/hair/pattern/mod.rs | 5 ----- src/test/ui/issue-74047.rs | 17 +++++++++++++++++ src/test/ui/issue-74047.stderr | 12 ++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issue-74047.rs create mode 100644 src/test/ui/issue-74047.stderr diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index 4fa23906a356..a5c87bc963f4 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -509,11 +509,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { let mut ty = self.typeck_results.node_type(pat.hir_id); - if let ty::Error(_) = ty.kind { - // Avoid ICEs (e.g., #50577 and #50585). - return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; - } - let kind = match pat.kind { hir::PatKind::Wild => PatKind::Wild, diff --git a/src/test/ui/issue-74047.rs b/src/test/ui/issue-74047.rs new file mode 100644 index 000000000000..2e4f3e675c3b --- /dev/null +++ b/src/test/ui/issue-74047.rs @@ -0,0 +1,17 @@ +// edition:2018 + +use std::convert::{TryFrom, TryInto}; +use std::io; + +pub struct MyStream; +pub struct OtherStream; + +pub async fn connect() -> io::Result { + let stream: MyStream = OtherStream.try_into()?; + Ok(stream) +} + +impl TryFrom for MyStream {} +//~^ ERROR: missing + +fn main() {} diff --git a/src/test/ui/issue-74047.stderr b/src/test/ui/issue-74047.stderr new file mode 100644 index 000000000000..6f477c77cedb --- /dev/null +++ b/src/test/ui/issue-74047.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Error`, `try_from` + --> $DIR/issue-74047.rs:14:1 + | +LL | impl TryFrom for MyStream {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation + | + = help: implement the missing item: `type Error = Type;` + = help: implement the missing item: `fn try_from(_: T) -> std::result::Result>::Error> { todo!() }` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. From ccbb024d8349183b8fba1743d24021f6e87f30cd Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 23 Jul 2020 03:07:26 +0000 Subject: [PATCH 16/17] ayu: Change to less luminous color Co-authored-by: Cldfire --- src/librustdoc/html/static/themes/ayu.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 96ba5c46a3cd..048f7d0ee75e 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -322,7 +322,7 @@ a.test-arrow:hover { :target > code, :target > .in-band { background: rgba(255, 236, 164, 0.06); - border-right: 3px solid #ffb44c; + border-right: 3px solid rgba(255, 180, 76, 0.85); } pre.compile_fail { From 7005ddb50d04727a70fd634d1645078134c96ea4 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 22 Jul 2020 14:46:33 +0000 Subject: [PATCH 17/17] Add right border bar to Dark and Light theme Ayu has it. Adding similar rule to other themes makes users less surprised and makes GUI more consistent. --- src/librustdoc/html/static/themes/dark.css | 1 + src/librustdoc/html/static/themes/light.css | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 33c0f885fa95..203acbfa65b5 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -270,6 +270,7 @@ a.test-arrow:hover{ :target > code, :target > .in-band { background-color: #494a3d; + border-right: 3px solid #bb7410; } pre.compile_fail { diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 569ce7da2091..e840d90f56a5 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -265,6 +265,7 @@ a.test-arrow:hover{ :target > code, :target > .in-band { background: #FDFFD3; + border-right: 3px solid #ffb44c; } pre.compile_fail {