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_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..62ccd734fe720 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,16 @@ 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 if sym::rustc_default_body_unstable == meta_name { + body_stab = + Some((DefaultBodyStability { level, feature }, attr.span)); + } else { + unreachable!("Unknown stability attribute {meta_name}"); } } (None, _, _) => { @@ -542,7 +565,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..7a9ad44d1d9ae 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() } @@ -416,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: \ @@ -423,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; @@ -492,6 +497,62 @@ 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; + } + + // 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; + } + + 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; + } + + 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/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)); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ca6a2ac3db34c..be920601ee43f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,8 +1,9 @@ //! 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, Stability, StabilityLevel, Unstable, UnstableReason, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { 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 +210,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + 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); + } + let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited @@ -613,6 +621,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(), }; @@ -673,6 +682,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 +735,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/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 9497d5c4528cc..0293bf7803a66 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,28 @@ 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, .. } => 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 => {} + } + } + + 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..b5201c737dfe3 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -122,13 +122,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 +663,37 @@ 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, +) { + 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}'"), + }; + + 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. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, 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..ecb281bccf604 --- /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 not all trait items implemented, missing: `CONSTANT` [E0046] +//~| ERROR not all trait items implemented, missing: `fun` [E0046] + +impl Equal for Type { + //~^ 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 new file mode 100644 index 0000000000000..ef666f30fc2a2 --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-err.stderr @@ -0,0 +1,38 @@ +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[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[E0046]: not all trait items implemented, missing: `eq` + --> $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 | | } + | |_^ + | + = 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 E0046`. 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 + } +}