From 177af4710464d9f743d64f8792afcb0ee553ba6b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 18:14:19 +0400 Subject: [PATCH 01/20] Implement `#[rustc_default_body_unstable]` This attribute allows to mark default body of a trait function as unstable. This means that implementing the trait without implementing the function will require enabling unstable feature. This is useful in conjunction with `#[rustc_must_implement_one_of]`, we may want to relax requirements for a trait, for example allowing implementing either of `PartialEq::{eq, ne}`, but do so in a safe way -- making implementation of only `PartialEq::ne` unstable. --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_attr/src/builtin.rs | 31 +++++++-- compiler/rustc_expand/src/base.rs | 13 +++- compiler/rustc_feature/src/builtin_attrs.rs | 4 ++ .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 13 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/middle/stability.rs | 64 ++++++++++++++++++- compiler/rustc_middle/src/query/mod.rs | 5 ++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_passes/src/stability.rs | 36 +++++++++-- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/check.rs | 30 +++++++-- compiler/rustc_typeck/src/check/mod.rs | 22 ++++++- 14 files changed, 206 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index ad9ed798e558b..3b58996e501d6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || attr.has_name(sym::stable) || attr.has_name(sym::rustc_const_unstable) || attr.has_name(sym::rustc_const_stable) + || attr.has_name(sym::rustc_default_body_unstable) { struct_span_err!( self.sess, diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 10a9cfb626e63..2eb50d648028e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -131,6 +131,14 @@ impl ConstStability { } } +/// Represents the `#[rustc_default_body_unstable]` attribute. +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic)] +pub struct DefaultBodyStability { + pub level: StabilityLevel, + pub feature: Symbol, +} + /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] @@ -214,7 +222,8 @@ pub fn find_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) +{ find_stability_generic(sess, attrs.iter(), item_sp) } @@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>( sess: &Session, attrs_iter: I, item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) where I: Iterator, { @@ -230,6 +239,7 @@ where let mut stab: Option<(Stability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None; + let mut body_stab: Option<(DefaultBodyStability, Span)> = None; let mut promotable = false; let mut allowed_through_unstable_modules = false; @@ -243,6 +253,7 @@ where sym::stable, sym::rustc_promotable, sym::rustc_allowed_through_unstable_modules, + sym::rustc_default_body_unstable, ] .iter() .any(|&s| attr.has_name(s)) @@ -280,7 +291,7 @@ where let meta_name = meta.name_or_empty(); match meta_name { - sym::rustc_const_unstable | sym::unstable => { + sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => { if meta_name == sym::unstable && stab.is_some() { handle_errors( &sess.parse_sess, @@ -295,6 +306,13 @@ where AttrError::MultipleStabilityLevels, ); break; + } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() { + handle_errors( + &sess.parse_sess, + attr.span, + AttrError::MultipleStabilityLevels, + ); + break; } let mut feature = None; @@ -405,11 +423,14 @@ where }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); - } else { + } else if sym::rustc_const_unstable == meta_name { const_stab = Some(( ConstStability { level, feature, promotable: false }, attr.span, )); + } else { + body_stab = + Some((DefaultBodyStability { level, feature }, attr.span)); } } (None, _, _) => { @@ -542,7 +563,7 @@ where } } - (stab, const_stab) + (stab, const_stab, body_stab) } pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 6e093811fcf6e..852ea806b20ff 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -772,7 +772,7 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - let (stability, const_stability) = attr::find_stability(&sess, attrs, span); + let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span); if let Some((_, sp)) = const_stability { sess.parse_sess .span_diagnostic @@ -784,6 +784,17 @@ impl SyntaxExtension { ) .emit(); } + if let Some((_, sp)) = body_stability { + sess.parse_sess + .span_diagnostic + .struct_span_err(sp, "macros cannot have body stability attributes") + .span_label(sp, "invalid body stability attribute") + .span_label( + sess.source_map().guess_head_span(span), + "body stability attribute affects this macro", + ) + .emit(); + } SyntaxExtension { kind, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c806df8214586..d8fd627c100d3 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), + ungated!( + rustc_default_body_unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk + ), gated!( allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, "allow_internal_unstable side-steps feature gating and stability checks", diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 65cae29c58dcb..35a6719a2fba6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, def_ident_span => { table } lookup_stability => { table } lookup_const_stability => { table } + lookup_default_body_stability => { table } lookup_deprecation_entry => { table } visibility => { table } unused_generic_params => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 50d983754e89c..f30f139584aa0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_stability(def_kind) { self.encode_stability(def_id); self.encode_const_stability(def_id); + self.encode_default_body_stability(def_id); self.encode_deprecation(def_id); } if should_encode_variances(def_kind) { @@ -1397,6 +1398,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_default_body_stability(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_default_body_stability({:?})", def_id); + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { + record!(self.tables.lookup_default_body_stability[def_id] <- stab) + } + } + } + fn encode_deprecation(&mut self, def_id: DefId) { debug!("EncodeContext::encode_deprecation({:?})", def_id); if let Some(depr) = self.tcx.lookup_deprecation(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0f291f9264777..a1d3c918ebdfc 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -343,6 +343,7 @@ define_tables! { def_ident_span: Table>, lookup_stability: Table>, lookup_const_stability: Table>, + lookup_default_body_stability: Table>, lookup_deprecation_entry: Table>, // As an optimization, a missing entry indicates an empty `&[]`. explicit_item_bounds: Table, Span)>>, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 414912dd0f7d8..24b74b7f65f52 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -5,7 +5,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, DefIdTree, TyCtxt}; use rustc_ast::NodeId; -use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; +use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; @@ -61,6 +61,7 @@ pub struct Index { /// are filled by the annotator. pub stab_map: FxHashMap, pub const_stab_map: FxHashMap, + pub default_body_stab_map: FxHashMap, pub depr_map: FxHashMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -86,6 +87,10 @@ impl Index { self.const_stab_map.get(&def_id).copied() } + pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { + self.default_body_stab_map.get(&def_id).copied() + } + pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { self.depr_map.get(&def_id).cloned() } @@ -492,6 +497,63 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Evaluates the default-impl stability of an item. + /// + /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding + /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending + /// unstable feature otherwise. + pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult { + let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some(); + if !is_staged_api { + return EvalResult::Allow; + } + + let stability = self.lookup_default_body_stability(def_id); + debug!( + "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" + ); + + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + + // Issue #38412: private items lack stability markers. + if skip_stability_check_due_to_privacy(self, def_id) { + return EvalResult::Allow; + } + + match stability { + Some(DefaultBodyStability { + level: attr::Unstable { reason, issue, is_soft, .. }, + feature, + }) => { + if span.allows_unstable(feature) { + debug!("body stability: skipping span={:?} since it is internal", span); + return EvalResult::Allow; + } + if self.features().active(feature) { + return EvalResult::Allow; + } + + //let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); + EvalResult::Deny { + feature, + reason: reason.to_opt_reason(), + issue, + suggestion: None, + is_soft, + } + } + Some(_) => { + // Stable APIs are always ok to call + EvalResult::Allow + } + None => EvalResult::Unmarked, + } + } + /// Checks if an item is stable or error out. /// /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 466a0fc25f7d1..0d03f506aac2b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1094,6 +1094,11 @@ rustc_queries! { separate_provide_extern } + query lookup_default_body_stability(def_id: DefId) -> Option { + desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query should_inherit_track_caller(def_id: DefId) -> bool { desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e189ee2fc4db1..ae6e2eecbffb5 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! { rustc_ast::Attribute, rustc_ast::MacArgs, rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, rustc_attr::Stability, rustc_hir::Constness, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ca6a2ac3db34c..2a3da4ec30e35 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,8 +1,10 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. -use attr::StabilityLevel; -use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason}; +use rustc_attr::{ + self as attr, ConstStability, DefaultBodyStability, Stability, StabilityLevel, Unstable, + UnstableReason, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -89,6 +91,7 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, + parent_body_stab: Option, parent_depr: Option, in_trait_impl: bool, } @@ -156,12 +159,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), None, None, + None, visit_children, ); return; } - let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); + let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); let mut const_span = None; let const_stab = const_stab.map(|(const_stab, const_span_node)| { @@ -209,6 +213,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + let body_stab = body_stab.map(|(body_stab, _span)| { + // FIXME: check that this item can have body stability + + self.index.default_body_stab_map.insert(def_id, body_stab); + debug!(?self.index.default_body_stab_map); + + body_stab + }); + let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited @@ -286,6 +299,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, if inherit_const_stability.yes() { const_stab } else { None }, + body_stab, visit_children, ); } @@ -295,12 +309,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr: Option, stab: Option, const_stab: Option, + body_stab: Option, 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; + let mut replaced_parent_body_stab = None; if let Some(depr) = depr { replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); @@ -312,6 +328,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); } + if let Some(body_stab) = body_stab { + replaced_parent_body_stab = Some(self.parent_body_stab.replace(body_stab)); + } f(self); @@ -324,6 +343,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } + if let Some(orig_parent_body_stab) = replaced_parent_body_stab { + self.parent_body_stab = orig_parent_body_stab; + } } } @@ -613,6 +635,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { stab_map: Default::default(), const_stab_map: Default::default(), + default_body_stab_map: Default::default(), depr_map: Default::default(), implications: Default::default(), }; @@ -623,6 +646,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, + parent_body_stab: None, parent_depr: None, in_trait_impl: false, }; @@ -673,6 +697,9 @@ pub(crate) fn provide(providers: &mut Providers) { stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), + lookup_default_body_stability: |tcx, id| { + tcx.stability().local_default_body_stability(id.expect_local()) + }, lookup_deprecation_entry: |tcx, id| { tcx.stability().local_deprecation_entry(id.expect_local()) }, @@ -723,7 +750,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api { let attrs = self.tcx.hir().attrs(item.hir_id()); - let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span); + let (stab, const_stab, _) = + attr::find_stability(&self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 54d67c5254188..036f087e2d23b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1215,6 +1215,7 @@ symbols! { rustc_const_unstable, rustc_conversion_suggestion, rustc_def_path, + rustc_default_body_unstable, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 9497d5c4528cc..6254825d96dc8 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -1104,12 +1105,31 @@ fn check_impl_items_against_trait<'tcx>( missing_items.push(tcx.associated_item(trait_item_id)); } - if let Some(required_items) = &must_implement_one_of { - // true if this item is specifically implemented in this impl - let is_implemented_here = ancestors - .leaf_def(tcx, trait_item_id) - .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + // true if this item is specifically implemented in this impl + let is_implemented_here = ancestors + .leaf_def(tcx, trait_item_id) + .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + + if !is_implemented_here { + match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { + EvalResult::Deny { feature, reason, issue, is_soft, .. } => { + default_body_is_unstable( + tcx, + full_impl_span, + trait_item_id, + feature, + reason, + issue, + is_soft, + ) + } + // Unmarked default bodies are considered stable (at least for now). + EvalResult::Allow | EvalResult::Unmarked => {} + } + } + + if let Some(required_items) = &must_implement_one_of { if is_implemented_here { let trait_item = tcx.associated_item(trait_item_id); if required_items.contains(&trait_item.ident(tcx)) { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 17c2e4868aac7..acd7e76fe2598 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,6 +99,7 @@ pub use expectation::Expectation; pub use fn_ctxt::*; use hir::def::CtorOf; pub use inherited::{Inherited, InheritedBuilder}; +use rustc_middle::middle::stability::report_unstable; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; @@ -122,13 +123,14 @@ use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{self, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use std::cell::RefCell; +use std::num::NonZeroU32; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -662,6 +664,24 @@ fn missing_items_must_implement_one_of_err( err.emit(); } +fn default_body_is_unstable( + tcx: TyCtxt<'_>, + impl_span: Span, + _item_did: DefId, + feature: Symbol, + reason: Option, + issue: Option, + is_soft: bool, +) { + let soft_handler = |lint, span, msg: &_| { + tcx.struct_span_lint_hir(lint, hir::CRATE_HIR_ID, span, |lint| { + lint.build(msg).emit(); + }) + }; + + report_unstable(tcx.sess, feature, reason, issue, None, is_soft, impl_span, soft_handler) +} + /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, From 9015a5110fd7b887dafaa1007afc02da90963f2a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 19:00:17 +0400 Subject: [PATCH 02/20] Collect features from `#[rustc_default_body_unstable]` --- compiler/rustc_passes/src/lib_features.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index e05994f13e4d9..868887c66cdec 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option, Span)> { - let stab_attrs = - [sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable]; + let stab_attrs = [ + sym::stable, + sym::unstable, + sym::rustc_const_stable, + sym::rustc_const_unstable, + sym::rustc_default_body_unstable, + ]; // Find a stability attribute: one of #[stable(…)], #[unstable(…)], - // #[rustc_const_stable(…)], or #[rustc_const_unstable(…)]. + // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable]. if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { let meta_kind = attr.meta_kind(); if let Some(MetaItemKind::List(ref metas)) = meta_kind { @@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> { // This additional check for stability is to make sure we // don't emit additional, irrelevant errors for malformed // attributes. - let is_unstable = - matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable); + let is_unstable = matches!( + *stab_attr, + sym::unstable + | sym::rustc_const_unstable + | sym::rustc_default_body_unstable + ); if since.is_some() || is_unstable { return Some((feature, since, attr.span)); } From d65fa276f3f2a239805f8458e210fb92fcfdca24 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 19:01:05 +0400 Subject: [PATCH 03/20] Add tests for `#[rustc_default_body_unstable]` --- .../auxiliary/default_body.rs | 29 +++++++++++++++++ .../default-body-stability-err.rs | 19 +++++++++++ .../default-body-stability-err.stderr | 32 +++++++++++++++++++ .../default-body-stability-ok-enables.rs | 18 +++++++++++ .../default-body-stability-ok-impls.rs | 21 ++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 src/test/ui/stability-attribute/auxiliary/default_body.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.stderr create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-enables.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-impls.rs diff --git a/src/test/ui/stability-attribute/auxiliary/default_body.rs b/src/test/ui/stability-attribute/auxiliary/default_body.rs new file mode 100644 index 0000000000000..3a177419d666d --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/default_body.rs @@ -0,0 +1,29 @@ +#![crate_type = "lib"] +#![feature(staged_api, rustc_attrs)] +#![stable(feature = "stable_feature", since = "1.0.0")] + +#[stable(feature = "stable_feature", since = "1.0.0")] +pub trait JustTrait { + #[stable(feature = "stable_feature", since = "1.0.0")] + #[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")] + const CONSTANT: usize = 0; + + #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")] + #[stable(feature = "stable_feature", since = "1.0.0")] + fn fun() {} +} + +#[rustc_must_implement_one_of(eq, neq)] +#[stable(feature = "stable_feature", since = "1.0.0")] +pub trait Equal { + #[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")] + #[stable(feature = "stable_feature", since = "1.0.0")] + fn eq(&self, other: &Self) -> bool { + !self.neq(other) + } + + #[stable(feature = "stable_feature", since = "1.0.0")] + fn neq(&self, other: &Self) -> bool { + !self.eq(other) + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-err.rs b/src/test/ui/stability-attribute/default-body-stability-err.rs new file mode 100644 index 0000000000000..8f970d0c9f661 --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-err.rs @@ -0,0 +1,19 @@ +// aux-build:default_body.rs +#![crate_type = "lib"] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type {} +//~^ ERROR use of unstable library feature 'fun_default_body' +//~| ERROR use of unstable library feature 'constant_default_body' + +impl Equal for Type { + //~^ ERROR use of unstable library feature 'eq_default_body' + fn neq(&self, other: &Self) -> bool { + false + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-err.stderr b/src/test/ui/stability-attribute/default-body-stability-err.stderr new file mode 100644 index 0000000000000..6abf68bbcae53 --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-err.stderr @@ -0,0 +1,32 @@ +error[E0658]: use of unstable library feature 'constant_default_body' + --> $DIR/default-body-stability-err.rs:10:1 + | +LL | impl JustTrait for Type {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(constant_default_body)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'fun_default_body' + --> $DIR/default-body-stability-err.rs:10:1 + | +LL | impl JustTrait for Type {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(fun_default_body)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'eq_default_body' + --> $DIR/default-body-stability-err.rs:14:1 + | +LL | / impl Equal for Type { +LL | | +LL | | fn neq(&self, other: &Self) -> bool { +LL | | false +LL | | } +LL | | } + | |_^ + | + = help: add `#![feature(eq_default_body)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs b/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs new file mode 100644 index 0000000000000..bdc7522f48dde --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs @@ -0,0 +1,18 @@ +// check-pass +// aux-build:default_body.rs +#![crate_type = "lib"] +#![feature(fun_default_body, eq_default_body, constant_default_body)] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type {} + +impl Equal for Type { + fn neq(&self, other: &Self) -> bool { + false + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs b/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs new file mode 100644 index 0000000000000..e1f5c017096ab --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs @@ -0,0 +1,21 @@ +// check-pass +// aux-build:default_body.rs +#![crate_type = "lib"] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type { + const CONSTANT: usize = 1; + + fn fun() {} +} + +impl Equal for Type { + fn eq(&self, other: &Self) -> bool { + false + } +} From 198443711501234a5d98b6d621aae2cead73c8cb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 20 Jun 2022 15:24:04 +0400 Subject: [PATCH 04/20] remove commented out code --- compiler/rustc_middle/src/middle/stability.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 24b74b7f65f52..0d1223ed28965 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -537,7 +537,6 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } - //let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); EvalResult::Deny { feature, reason: reason.to_opt_reason(), From 1e1d6fe84dd086a9075fcfe5fc63d81738c02f12 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 20 Jun 2022 16:07:14 +0400 Subject: [PATCH 05/20] Improve error message for unstable default body --- Cargo.lock | 1 + compiler/rustc_typeck/Cargo.toml | 1 + compiler/rustc_typeck/src/check/check.rs | 19 ++++++------- compiler/rustc_typeck/src/check/mod.rs | 28 +++++++++++++------ .../default-body-stability-err.rs | 6 ++-- .../default-body-stability-err.stderr | 14 +++++++--- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed3e30342f2f6..bb7598bbf3e6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4616,6 +4616,7 @@ dependencies = [ "rustc_attr", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_graphviz", "rustc_hir", "rustc_hir_pretty", diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index faf52e2695a33..cae29c1d3c5f9 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" } rustc_lint = { path = "../rustc_lint" } rustc_serialize = { path = "../rustc_serialize" } rustc_type_ir = { path = "../rustc_type_ir" } +rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6254825d96dc8..0293bf7803a66 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1112,17 +1112,14 @@ fn check_impl_items_against_trait<'tcx>( if !is_implemented_here { match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { - EvalResult::Deny { feature, reason, issue, is_soft, .. } => { - default_body_is_unstable( - tcx, - full_impl_span, - trait_item_id, - feature, - reason, - issue, - is_soft, - ) - } + EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( + tcx, + full_impl_span, + trait_item_id, + feature, + reason, + issue, + ), // Unmarked default bodies are considered stable (at least for now). EvalResult::Allow | EvalResult::Unmarked => {} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index acd7e76fe2598..b5201c737dfe3 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,7 +99,6 @@ pub use expectation::Expectation; pub use fn_ctxt::*; use hir::def::CtorOf; pub use inherited::{Inherited, InheritedBuilder}; -use rustc_middle::middle::stability::report_unstable; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; @@ -667,19 +666,32 @@ fn missing_items_must_implement_one_of_err( fn default_body_is_unstable( tcx: TyCtxt<'_>, impl_span: Span, - _item_did: DefId, + item_did: DefId, feature: Symbol, reason: Option, issue: Option, - is_soft: bool, ) { - let soft_handler = |lint, span, msg: &_| { - tcx.struct_span_lint_hir(lint, hir::CRATE_HIR_ID, span, |lint| { - lint.build(msg).emit(); - }) + let missing_item_name = &tcx.associated_item(item_did).name; + let use_of_unstable_library_feature_note = match reason { + Some(r) => format!("use of unstable library feature '{feature}': {r}"), + None => format!("use of unstable library feature '{feature}'"), }; - report_unstable(tcx.sess, feature, reason, issue, None, is_soft, impl_span, soft_handler) + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0046, + "not all trait items implemented, missing: `{missing_item_name}`", + ); + err.note(format!("default implementation of `{missing_item_name}` is unstable")); + err.note(use_of_unstable_library_feature_note); + rustc_session::parse::add_feature_diagnostics_for_issue( + &mut err, + &tcx.sess.parse_sess, + feature, + rustc_feature::GateIssue::Library(issue), + ); + err.emit(); } /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. diff --git a/src/test/ui/stability-attribute/default-body-stability-err.rs b/src/test/ui/stability-attribute/default-body-stability-err.rs index 8f970d0c9f661..ecb281bccf604 100644 --- a/src/test/ui/stability-attribute/default-body-stability-err.rs +++ b/src/test/ui/stability-attribute/default-body-stability-err.rs @@ -8,11 +8,11 @@ use default_body::{Equal, JustTrait}; struct Type; impl JustTrait for Type {} -//~^ ERROR use of unstable library feature 'fun_default_body' -//~| ERROR use of unstable library feature 'constant_default_body' +//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046] +//~| ERROR not all trait items implemented, missing: `fun` [E0046] impl Equal for Type { - //~^ ERROR use of unstable library feature 'eq_default_body' + //~^ ERROR not all trait items implemented, missing: `eq` [E0046] fn neq(&self, other: &Self) -> bool { false } diff --git a/src/test/ui/stability-attribute/default-body-stability-err.stderr b/src/test/ui/stability-attribute/default-body-stability-err.stderr index 6abf68bbcae53..ef666f30fc2a2 100644 --- a/src/test/ui/stability-attribute/default-body-stability-err.stderr +++ b/src/test/ui/stability-attribute/default-body-stability-err.stderr @@ -1,20 +1,24 @@ -error[E0658]: use of unstable library feature 'constant_default_body' +error[E0046]: not all trait items implemented, missing: `CONSTANT` --> $DIR/default-body-stability-err.rs:10:1 | LL | impl JustTrait for Type {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: default implementation of `CONSTANT` is unstable + = note: use of unstable library feature 'constant_default_body' = help: add `#![feature(constant_default_body)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'fun_default_body' +error[E0046]: not all trait items implemented, missing: `fun` --> $DIR/default-body-stability-err.rs:10:1 | LL | impl JustTrait for Type {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: default implementation of `fun` is unstable + = note: use of unstable library feature 'fun_default_body' = help: add `#![feature(fun_default_body)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'eq_default_body' +error[E0046]: not all trait items implemented, missing: `eq` --> $DIR/default-body-stability-err.rs:14:1 | LL | / impl Equal for Type { @@ -25,8 +29,10 @@ LL | | } LL | | } | |_^ | + = note: default implementation of `eq` is unstable + = note: use of unstable library feature 'eq_default_body' = help: add `#![feature(eq_default_body)]` to the crate attributes to enable error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0046`. From 95729dcc733edd9f639855081cae8e24bc44fb30 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 14:34:26 +0100 Subject: [PATCH 06/20] check_missing_items.py: Don't overwrite `ty` in loop Because python doesn't have lexical scope, loop variables persist after the loop is exited, set to the value of the last itteration ``` >>> i = 0 >>> for i in range(10): pass ... >>> i 9 ``` This causes the `ty` variable to be changed, causing unexpected crashes on ``` pub type RefFn<'a> = &'a dyn for<'b> Fn(&'a i32) -> i32; ``` --- src/etc/check_missing_items.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 343dd0387f479..a705e2384959f 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -88,8 +88,8 @@ def check_type(ty): for bound in binding["binding"]["constraint"]: check_generic_bound(bound) elif "parenthesized" in args: - for ty in args["parenthesized"]["inputs"]: - check_type(ty) + for input_ty in args["parenthesized"]["inputs"]: + check_type(input_ty) if args["parenthesized"]["output"]: check_type(args["parenthesized"]["output"]) if not valid_id(ty["inner"]["id"]): From 2143e48e36e48223e00fffed71acadaf5330f61a Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 15:02:01 +0100 Subject: [PATCH 07/20] Rustdoc-Json: Add tests for dyn and HRTBs --- src/test/rustdoc-json/type/dyn.rs | 19 +++++++++++++++++-- src/test/rustdoc-json/type/hrtb.rs | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-json/type/hrtb.rs diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs index f53dc03f4b47f..79eeb996dcc5d 100644 --- a/src/test/rustdoc-json/type/dyn.rs +++ b/src/test/rustdoc-json/type/dyn.rs @@ -1,8 +1,10 @@ // ignore-tidy-linelength -// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1 +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 2 // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" -// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen +// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn // @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' @@ -19,3 +21,16 @@ // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; + +// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\" +// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" +pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; diff --git a/src/test/rustdoc-json/type/hrtb.rs b/src/test/rustdoc-json/type/hrtb.rs new file mode 100644 index 0000000000000..55bc043ad29cd --- /dev/null +++ b/src/test/rustdoc-json/type/hrtb.rs @@ -0,0 +1,23 @@ + +// @has hrtb.json + +// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}' +// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +pub fn genfn(f: F) +where + for<'a, 'b> F: Fn(&'a i32, &'b i32), +{ + let zero = 0; + f(&zero, &zero); +} + +// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.name" '"Fn"' +pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { + let zero = 0; + f(&zero, &zero); +} From e11b4b8e02495e9753df983de7bcec9ef2b8ae31 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 31 Jul 2022 16:02:45 +0400 Subject: [PATCH 08/20] Panic when checking an unknown stability attribute --- compiler/rustc_attr/src/builtin.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2eb50d648028e..62ccd734fe720 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -428,9 +428,11 @@ where ConstStability { level, feature, promotable: false }, attr.span, )); - } else { + } else if sym::rustc_default_body_unstable == meta_name { body_stab = Some((DefaultBodyStability { level, feature }, attr.span)); + } else { + unreachable!("Unknown stability attribute {meta_name}"); } } (None, _, _) => { From 963e402f4384806a4cfb9020208287972e5534d2 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 31 Jul 2022 16:29:31 +0400 Subject: [PATCH 09/20] Don't track parent body stability (it wasn't used anyway) --- compiler/rustc_passes/src/stability.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 2a3da4ec30e35..be920601ee43f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -2,8 +2,7 @@ //! propagating default levels lexically from parent to children ast nodes. use rustc_attr::{ - self as attr, ConstStability, DefaultBodyStability, Stability, StabilityLevel, Unstable, - UnstableReason, + self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; @@ -91,7 +90,6 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - parent_body_stab: Option, parent_depr: Option, in_trait_impl: bool, } @@ -159,7 +157,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), None, None, - None, visit_children, ); return; @@ -213,14 +210,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - let body_stab = body_stab.map(|(body_stab, _span)| { + if let Some((body_stab, _span)) = body_stab { // FIXME: check that this item can have body stability self.index.default_body_stab_map.insert(def_id, body_stab); debug!(?self.index.default_body_stab_map); - - body_stab - }); + } let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. @@ -299,7 +294,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, if inherit_const_stability.yes() { const_stab } else { None }, - body_stab, visit_children, ); } @@ -309,14 +303,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr: Option, stab: Option, const_stab: Option, - body_stab: Option, 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; - let mut replaced_parent_body_stab = None; if let Some(depr) = depr { replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); @@ -328,9 +320,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); } - if let Some(body_stab) = body_stab { - replaced_parent_body_stab = Some(self.parent_body_stab.replace(body_stab)); - } f(self); @@ -343,9 +332,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } - if let Some(orig_parent_body_stab) = replaced_parent_body_stab { - self.parent_body_stab = orig_parent_body_stab; - } } } @@ -646,7 +632,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, - parent_body_stab: None, parent_depr: None, in_trait_impl: false, }; From a856e57f6cc8ba8bb83c5abadce338f589df6b10 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 17:51:55 +0100 Subject: [PATCH 10/20] Rustdoc-Json: Document HRTB's on DynTrait Closes #99118 --- src/librustdoc/json/conversions.rs | 48 ++++++++++++++---------------- src/rustdoc-json-types/lib.rs | 38 ++++++++++++++++++++--- src/test/rustdoc-json/type/dyn.rs | 45 ++++++++++++++++++---------- src/test/rustdoc-json/type/hrtb.rs | 9 ++++-- 4 files changed, 91 insertions(+), 49 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 716a4c9ea4319..f5c089ce1e4bf 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -244,7 +244,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)), TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)), - ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), + ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, @@ -447,8 +447,8 @@ pub(crate) fn from_trait_bound_modifier( impl FromWithTcx for Type { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::{ - Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, - QPath, RawPointer, Slice, Tuple, + Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, + RawPointer, Slice, Tuple, }; match ty { @@ -458,26 +458,10 @@ impl FromWithTcx for Type { args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), param_names: Vec::new(), }, - DynTrait(mut bounds, lt) => { - let first_trait = bounds.remove(0).trait_; - - Type::ResolvedPath { - name: first_trait.whole_name(), - id: from_item_id(first_trait.def_id().into(), tcx), - args: first_trait - .segments - .last() - .map(|args| Box::new(args.clone().args.into_tcx(tcx))), - param_names: bounds - .into_iter() - .map(|t| { - clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None) - }) - .chain(lt.map(clean::GenericBound::Outlives)) - .map(|bound| bound.into_tcx(tcx)) - .collect(), - } - } + clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { + lifetime: lt.map(|lt| lt.0.to_string()), + traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), + }), Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), @@ -568,10 +552,22 @@ impl FromWithTcx for Trait { } } -impl FromWithTcx> for Impl { - fn from_tcx(impl_: Box, tcx: TyCtxt<'_>) -> Self { +impl FromWithTcx for PolyTrait { + fn from_tcx( + clean::PolyTrait { trait_, generic_params }: clean::PolyTrait, + tcx: TyCtxt<'_>, + ) -> Self { + PolyTrait { + trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx), + generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + } + } +} + +impl FromWithTcx for Impl { + fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { let provided_trait_methods = impl_.provided_trait_methods(tcx); - let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_; + let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_; // FIXME: should `trait_` be a clean::Path equivalent in JSON? let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx)); // FIXME: use something like ImplKind in JSON? diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 761e94c7ebbc4..bd4ea98441d66 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 16; +pub const FORMAT_VERSION: u32 = 17; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -115,6 +115,35 @@ pub enum Visibility { }, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct DynTrait { + /// All the traits implemented. One of them is the vtable, and the rest must be auto traits. + pub traits: Vec, + /// The lifetime of the whole dyn object + /// ```text + /// dyn Debug + 'static + /// ^^^^^^^ + /// | + /// this part + /// ``` + pub lifetime: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +/// A trait and potential HRTBs +pub struct PolyTrait { + #[serde(rename = "trait")] + pub trait_: Type, + /// Used for Higher-Rank Trait Bounds (HRTBs) + /// ```text + /// dyn for<'a> Fn() -> &'a i32" + /// ^^^^^^^ + /// | + /// this part + /// ``` + pub generic_params: Vec, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericArgs { @@ -395,7 +424,7 @@ pub enum WherePredicate { type_: Type, bounds: Vec, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// where for<'a> &'a T: Iterator," /// ^^^^^^^ /// | @@ -420,7 +449,7 @@ pub enum GenericBound { #[serde(rename = "trait")] trait_: Type, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// where F: for<'a, 'b> Fn(&'a u8, &'b u8) /// ^^^^^^^^^^^ /// | @@ -458,6 +487,7 @@ pub enum Type { args: Option>, param_names: Vec, }, + DynTrait(DynTrait), /// Parameterized types Generic(String), /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples @@ -505,7 +535,7 @@ pub enum Type { pub struct FunctionPointer { pub decl: FnDecl, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// for<'c> fn(val: &'c i32) -> i32 /// ^^^^^^^ /// | diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs index 79eeb996dcc5d..c18b54d1fdf0e 100644 --- a/src/test/rustdoc-json/type/dyn.rs +++ b/src/test/rustdoc-json/type/dyn.rs @@ -1,10 +1,13 @@ // ignore-tidy-linelength +use std::fmt::Debug; -// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 2 +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3 // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" -// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @set weird_order = - "$.index[*][?(@.name=='WeirdOrder')].id" // @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen // @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order // @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' @@ -12,14 +15,16 @@ // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] // @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\" -// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3 -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\" +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; // @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\" @@ -27,10 +32,18 @@ pub type SyncIntGen = Box i32 + Send + Sync + 'static>; // @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"' // @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false' // @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\"" -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"resolved_path"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.name" '"Fn"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null +// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1 +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; + +// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"' +// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"' +pub type WeirdOrder = Box; diff --git a/src/test/rustdoc-json/type/hrtb.rs b/src/test/rustdoc-json/type/hrtb.rs index 55bc043ad29cd..9311737be0fec 100644 --- a/src/test/rustdoc-json/type/hrtb.rs +++ b/src/test/rustdoc-json/type/hrtb.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // @has hrtb.json @@ -14,9 +15,11 @@ where // @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' // @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' // @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"resolved_path"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null +// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1 +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); From 625c4d70ffa53e36d2b724d191f759937a131bff Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 17:55:40 +0100 Subject: [PATCH 11/20] Rustdoc-Json: Extract `convert_lifetime` to function --- src/librustdoc/json/conversions.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f5c089ce1e4bf..8d63c3409c270 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -145,7 +145,7 @@ impl FromWithTcx for GenericArg { fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { use clean::GenericArg::*; match arg { - Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), + Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), Type(t) => GenericArg::Type(t.into_tcx(tcx)), Const(box c) => GenericArg::Const(c.into_tcx(tcx)), Infer => GenericArg::Infer, @@ -347,6 +347,10 @@ fn convert_abi(a: RustcAbi) -> Abi { } } +fn convert_lifetime(l: clean::Lifetime) -> String { + l.0.to_string() +} + impl FromWithTcx for Generics { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { @@ -374,7 +378,7 @@ impl FromWithTcx for GenericParamDefKind { use clean::GenericParamDefKind::*; match kind { Lifetime { outlives } => GenericParamDefKind::Lifetime { - outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), + outlives: outlives.into_iter().map(convert_lifetime).collect(), }, Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), @@ -405,7 +409,7 @@ impl FromWithTcx for WherePredicate { .collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { - lifetime: lifetime.0.to_string(), + lifetime: convert_lifetime(lifetime) bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), }, EqPredicate { lhs, rhs } => { @@ -428,7 +432,7 @@ impl FromWithTcx for GenericBound { modifier: from_trait_bound_modifier(modifier), } } - Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()), + Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), } } } @@ -459,7 +463,7 @@ impl FromWithTcx for Type { param_names: Vec::new(), }, clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { - lifetime: lt.map(|lt| lt.0.to_string()), + lifetime: lt.map(convert_lifetime), traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), }), Generic(s) => Type::Generic(s.to_string()), @@ -475,7 +479,7 @@ impl FromWithTcx for Type { type_: Box::new((*type_).into_tcx(tcx)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { - lifetime: lifetime.map(|l| l.0.to_string()), + lifetime: lifetime.map(convert_lifetime), mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, From 6290f92d07fd7ecdbd2f752fde9b12f926b592fa Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 27 Jul 2022 00:58:59 +0100 Subject: [PATCH 12/20] Rustdoc-Json: Add and use `FromWithTcx` for `Vec` --- src/librustdoc/json/conversions.rs | 64 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 8d63c3409c270..8caba8cb9029c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -119,6 +119,16 @@ where } } +impl FromWithTcx for Vec +where + I: IntoIterator, + U: FromWithTcx, +{ + fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec { + f.into_iter().map(|x| x.into_tcx(tcx)).collect() + } +} + pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { #[rustfmt::skip] let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; @@ -130,11 +140,11 @@ impl FromWithTcx for GenericArgs { use clean::GenericArgs::*; match args { AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { - args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), - bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(), + args: args.into_vec().into_tcx(tcx), + bindings: bindings.into_tcx(tcx), }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { - inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), + inputs: inputs.into_vec().into_tcx(tcx), output: output.map(|a| (*a).into_tcx(tcx)), }, } @@ -177,9 +187,7 @@ impl FromWithTcx for TypeBindingKind { use clean::TypeBindingKind::*; match kind { Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)), - Constraint { bounds } => { - TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) - } + Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)), } } } @@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { } TyAssocTypeItem(g, b) => ItemEnum::AssocType { generics: (*g).into_tcx(tcx), - bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: b.into_tcx(tcx), default: None, }, AssocTypeItem(t, b) => ItemEnum::AssocType { generics: t.generics.into_tcx(tcx), - bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: b.into_tcx(tcx), default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), }, // `convert_item` early returns `None` for stripped items and keywords. @@ -354,12 +362,8 @@ fn convert_lifetime(l: clean::Lifetime) -> String { impl FromWithTcx for Generics { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { - params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(), - where_predicates: generics - .where_predicates - .into_iter() - .map(|x| x.into_tcx(tcx)) - .collect(), + params: generics.params.into_tcx(tcx), + where_predicates: generics.where_predicates.into_tcx(tcx), } } } @@ -381,7 +385,7 @@ impl FromWithTcx for GenericParamDefKind { outlives: outlives.into_iter().map(convert_lifetime).collect(), }, Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, @@ -399,7 +403,7 @@ impl FromWithTcx for WherePredicate { match predicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { type_: ty.into_tcx(tcx), - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), generic_params: bound_params .into_iter() .map(|x| GenericParamDef { @@ -409,8 +413,8 @@ impl FromWithTcx for WherePredicate { .collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { - lifetime: convert_lifetime(lifetime) - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + lifetime: convert_lifetime(lifetime), + bounds: bounds.into_tcx(tcx), }, EqPredicate { lhs, rhs } => { WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } @@ -428,7 +432,7 @@ impl FromWithTcx for GenericBound { let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx); GenericBound::TraitBound { trait_, - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), modifier: from_trait_bound_modifier(modifier), } } @@ -464,15 +468,15 @@ impl FromWithTcx for Type { }, clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { lifetime: lt.map(convert_lifetime), - traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), + traits: bounds.into_tcx(tcx), }), Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), - Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), + Tuple(t) => Type::Tuple(t.into_tcx(tcx)), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, - ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), + ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { mutable: mutability == ast::Mutability::Mut, @@ -516,7 +520,7 @@ impl FromWithTcx for FunctionPointer { async_: false, abi: convert_abi(abi), }, - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), decl: decl.into_tcx(tcx), } } @@ -550,7 +554,7 @@ impl FromWithTcx for Trait { is_unsafe, items: ids(items, tcx), generics: generics.into_tcx(tcx), - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), implementations: Vec::new(), // Added in JsonRenderer::item } } @@ -563,7 +567,7 @@ impl FromWithTcx for PolyTrait { ) -> Self { PolyTrait { trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx), - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), } } } @@ -730,10 +734,7 @@ impl FromWithTcx> for Typedef { impl FromWithTcx for OpaqueTy { fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self { - OpaqueTy { - bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), - generics: opaque.generics.into_tcx(tcx), - } + OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) } } } @@ -749,10 +750,7 @@ impl FromWithTcx for Static { impl FromWithTcx for TraitAlias { fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { - TraitAlias { - generics: alias.generics.into_tcx(tcx), - params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), - } + TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) } } } From 95bf0fb917577c61e4a9d41d837e6fa132515b3d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 5 Aug 2022 18:13:22 +0400 Subject: [PATCH 13/20] Move stability lookup after cross-crate check --- compiler/rustc_middle/src/middle/stability.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 0d1223ed28965..7a9ad44d1d9ae 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -421,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + let stability = self.lookup_stability(def_id); debug!( "stability: \ @@ -428,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> { def_id, span, stability ); - // Only the cross-crate scenario matters when checking unstable APIs - let cross_crate = !def_id.is_local(); - if !cross_crate { - return EvalResult::Allow; - } - // Issue #38412: private items lack stability markers. if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; @@ -508,17 +508,17 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } - let stability = self.lookup_default_body_stability(def_id); - debug!( - "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" - ); - // Only the cross-crate scenario matters when checking unstable APIs let cross_crate = !def_id.is_local(); if !cross_crate { return EvalResult::Allow; } + let stability = self.lookup_default_body_stability(def_id); + debug!( + "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" + ); + // Issue #38412: private items lack stability markers. if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; From d5e9e94741fd16320f5491397645fb137195eb06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 16:39:06 -0400 Subject: [PATCH 14/20] add method to get the mutability of an AllocId --- compiler/rustc_const_eval/src/interpret/memory.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ed2c4edf9dd72..75528d6140ce5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -520,6 +520,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Gives raw access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! + /// + /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. fn get_alloc_raw( &self, id: AllocId, @@ -589,6 +591,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(&self.get_alloc_raw(id)?.extra) } + /// Return the `mutability` field of the given allocation. + pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { + Ok(self.get_alloc_raw(id)?.mutability) + } + /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! /// From 54b122e9132937bb0aa3514b3d5852b68e7ddf04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:59:47 -0400 Subject: [PATCH 15/20] propagate --bless to Miri --- src/bootstrap/test.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 05403cf48c7c5..782cbd8f5ffad 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -628,6 +628,10 @@ impl Step for Miri { cargo.env("MIRI_HOST_SYSROOT", sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", miri); + // propagate --bless + if builder.config.cmd.bless() { + cargo.env("MIRI_BLESS", "Gesundheit"); + } cargo.arg("--").args(builder.config.cmd.test_args()); From fc83a0cb57eaad7104cc8861ba354fc76da79684 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 7 Aug 2022 04:03:28 -0700 Subject: [PATCH 16/20] Don't ICE while suggesting updating item path. When an item isn't found, we may suggest an appropriate import to `use`. Along with that, we also suggest updating the path to work with the `use`. Unfortunately, if the code in question originates from a macro, the span used to indicate which part of the path needs updating may not be suitable and cause an ICE. Since, such code is not adjustable directly by the user without modifying the macro, just skip the suggestion in such cases. --- compiler/rustc_resolve/src/diagnostics.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8839fb1a15120..325b0458638af 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2544,12 +2544,15 @@ fn show_candidates( Applicability::MaybeIncorrect, ); if let [first, .., last] = &path[..] { - err.span_suggestion_verbose( - first.ident.span.until(last.ident.span), - &format!("if you import `{}`, refer to it directly", last.ident), - "", - Applicability::Unspecified, - ); + let sp = first.ident.span.until(last.ident.span); + if sp.can_be_used_for_suggestions() { + err.span_suggestion_verbose( + sp, + &format!("if you import `{}`, refer to it directly", last.ident), + "", + Applicability::Unspecified, + ); + } } } else { msg.push(':'); From 15b1daaca3fd4020d7a93cff14507b9104ec6d02 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 7 Aug 2022 13:55:36 -0700 Subject: [PATCH 17/20] Add UI test for #100199 --- src/test/ui/macros/auxiliary/issue-100199.rs | 18 ++++++++++++++++++ src/test/ui/macros/issue-100199.rs | 16 ++++++++++++++++ src/test/ui/macros/issue-100199.stderr | 15 +++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/test/ui/macros/auxiliary/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.stderr diff --git a/src/test/ui/macros/auxiliary/issue-100199.rs b/src/test/ui/macros/auxiliary/issue-100199.rs new file mode 100644 index 0000000000000..9e190b542db49 --- /dev/null +++ b/src/test/ui/macros/auxiliary/issue-100199.rs @@ -0,0 +1,18 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::{quote, Ident, Span, TokenStream, TokenTree}; + +#[proc_macro_attribute] +pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream { + let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site())); + let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site())); + quote!( + struct Foo {} + ) +} diff --git a/src/test/ui/macros/issue-100199.rs b/src/test/ui/macros/issue-100199.rs new file mode 100644 index 0000000000000..6e50afa075984 --- /dev/null +++ b/src/test/ui/macros/issue-100199.rs @@ -0,0 +1,16 @@ +#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root +struct Foo {} +// The above must be on the first line so that it's span points to pos 0. +// This used to trigger an ICE because the diagnostic emitter would get +// an unexpected dummy span (lo == 0 == hi) while attempting to print a +// suggestion. + +// aux-build: issue-100199.rs + +extern crate issue_100199; + +mod traits { + pub trait MyTrait {} +} + +fn main() {} diff --git a/src/test/ui/macros/issue-100199.stderr b/src/test/ui/macros/issue-100199.stderr new file mode 100644 index 0000000000000..2cb45dc12473e --- /dev/null +++ b/src/test/ui/macros/issue-100199.stderr @@ -0,0 +1,15 @@ +error[E0405]: cannot find trait `MyTrait` in the crate root + --> $DIR/issue-100199.rs:1:1 + | +LL | #[issue_100199::struct_with_bound] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root + | + = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider importing this trait + | +LL | use traits::MyTrait; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0405`. From b3b23aada9382e7768c0bd4d8f79319d73558259 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Aug 2022 05:47:32 +0000 Subject: [PATCH 18/20] Don't document impossible to call default trait items on impls --- compiler/rustc_middle/src/query/mod.rs | 8 ++ .../rustc_trait_selection/src/traits/mod.rs | 78 ++++++++++++++++++- src/librustdoc/html/render/mod.rs | 9 +++ src/test/rustdoc/impossible-default.rs | 20 +++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/impossible-default.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d8483e7e40914..9db193dc0cefa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1951,6 +1951,14 @@ rustc_queries! { } } + query is_impossible_method(key: (DefId, DefId)) -> bool { + desc { |tcx| + "checking if {} is impossible to call within {}", + tcx.def_path_str(key.1), + tcx.def_path_str(key.0), + } + } + query method_autoderef_steps( goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9c6bb0731f441..06aeafa26c05b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -30,10 +30,14 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; +use rustc_middle::ty::{ + self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, + VtblEntry, +}; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -474,6 +478,77 @@ fn subst_and_check_impossible_predicates<'tcx>( result } +/// Checks whether a trait's method is impossible to call on a given impl. +/// +/// This only considers predicates that reference the impl's generics, and not +/// those that reference the method's generics. +fn is_impossible_method<'tcx>( + tcx: TyCtxt<'tcx>, + (impl_def_id, trait_item_def_id): (DefId, DefId), +) -> bool { + struct ReferencesOnlyParentGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + trait_item_def_id: DefId, + } + impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + // If this is a parameter from the trait item's own generics, then bail + if let ty::Param(param) = t.kind() + && let param_def_id = self.generics.type_param(param, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + t.super_visit_with(self) + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::ReEarlyBound(param) = r.kind() + && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + r.super_visit_with(self) + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + if let ty::ConstKind::Param(param) = ct.kind() + && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + ct.super_visit_with(self) + } + } + + let generics = tcx.generics_of(trait_item_def_id); + let predicates = tcx.predicates_of(trait_item_def_id); + let impl_trait_ref = + tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait"); + let param_env = tcx.param_env(impl_def_id); + + let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; + let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { + if pred.visit_with(&mut visitor).is_continue() { + Some(Obligation::new( + ObligationCause::dummy_with_span(*span), + param_env, + ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), + )) + } else { + None + } + }); + + tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| { + let mut fulfill_ctxt = >::new(tcx); + fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait); + !fulfill_ctxt.select_all_or_error(infcx).is_empty() + }) +} + #[derive(Clone, Debug)] enum VtblSegment<'tcx> { MetadataDSA, @@ -854,6 +929,7 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, + is_impossible_method, try_unify_abstract_consts: |tcx, param_env_and| { let (param_env, (a, b)) = param_env_and.into_parts(); const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a262c8f7d1948..ae7d8c108d3ee 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1550,6 +1550,15 @@ fn render_impl( rendering_params: ImplRenderingParameters, ) { for trait_item in &t.items { + // Skip over any default trait items that are impossible to call + // (e.g. if it has a `Self: Sized` bound on an unsized type). + if let Some(impl_def_id) = parent.item_id.as_def_id() + && let Some(trait_item_def_id) = trait_item.item_id.as_def_id() + && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id)) + { + continue; + } + let n = trait_item.name; if i.items.iter().any(|m| m.name == n) { continue; diff --git a/src/test/rustdoc/impossible-default.rs b/src/test/rustdoc/impossible-default.rs new file mode 100644 index 0000000000000..24d6e3bdac1bd --- /dev/null +++ b/src/test/rustdoc/impossible-default.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +// Check that default trait items that are impossible to satisfy + +pub trait Foo { + fn needs_sized(&self) + where + Self: Sized, + {} + + fn no_needs_sized(&self) {} +} + +// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \ +// "fn needs_sized" +// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \ +// "fn no_needs_sized" +pub struct Bar([u8]); + +impl Foo for Bar {} From abbd34d00e0a5ee15060ef92dc6b0225dd2897a5 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 9 Aug 2022 12:27:53 +0900 Subject: [PATCH 19/20] avoid `&str` to `String` conversions --- compiler/rustc_typeck/src/check/coercion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 21d0a7869d68e..540a8c3a83d95 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1589,11 +1589,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ) { let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; let mut span: MultiSpan = vec![loop_span].into(); - span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string()); + span.push_span_label(loop_span, "this might have zero elements to iterate on"); for ret_expr in ret_exprs { span.push_span_label( ret_expr.span, - "if the loop doesn't execute, this value would never get returned".to_string(), + "if the loop doesn't execute, this value would never get returned", ); } err.span_note( From 56ec5bec1ee9ecf6cbacb2378dbc75238a9fc8fe Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 9 Aug 2022 14:27:26 +0900 Subject: [PATCH 20/20] suggest adding an appropriate missing pattern excluding comments --- .../src/thir/pattern/check_match.rs | 28 +++++++++---------- ...e-missing-pattern-excluding-comments.fixed | 10 +++++++ ...iate-missing-pattern-excluding-comments.rs | 9 ++++++ ...-missing-pattern-excluding-comments.stderr | 24 ++++++++++++++++ 4 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 063c076474e90..69a8c98b27a3d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>( )); } [.., prev, last] if prev.span.eq_ctxt(last.span) => { - if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) { - let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) - && last.span.eq_ctxt(last.body.span) - { - "" - } else { - "," - }; + let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) + && last.span.eq_ctxt(last.body.span) + { + "" + } else { + "," + }; + let spacing = if sm.is_multiline(prev.span.between(last.span)) { + sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) + } else { + Some(" ".to_string()) + }; + if let Some(spacing) = spacing { suggestion = Some(( last.span.shrink_to_hi(), - format!( - "{}{}{} => todo!()", - comma, - snippet.strip_prefix(',').unwrap_or(&snippet), - pattern - ), + format!("{}{}{} => todo!()", comma, spacing, pattern), )); } } diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed new file mode 100644 index 0000000000000..b28dce8810593 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +fn main() { + match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered + Some(1) => {} + // hello + Some(_) => {} + None => todo!() + } +} diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs new file mode 100644 index 0000000000000..42493a6327173 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered + Some(1) => {} + // hello + Some(_) => {} + } +} diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr new file mode 100644 index 0000000000000..f3dca9bcb07d1 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11 + | +LL | match Some(1) { + | ^^^^^^^ pattern `None` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option { + | ------------------ +... +LL | None, + | ^^^^ not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Some(_) => {} +LL + None => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`.