Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -4616,6 +4616,7 @@ dependencies = [
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_pretty",
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -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,
33 changes: 28 additions & 5 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -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,22 +222,24 @@ 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)
}

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<Item = &'a Attribute>,
{
use StabilityLevel::*;

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<Symbol> {
13 changes: 12 additions & 1 deletion compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
@@ -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",
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
@@ -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 }
13 changes: 13 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
@@ -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) {
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
@@ -343,6 +343,7 @@ define_tables! {
def_ident_span: Table<DefIndex, LazyValue<Span>>,
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
75 changes: 68 additions & 7 deletions compiler/rustc_middle/src/middle/stability.rs
Original file line number Diff line number Diff line change
@@ -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<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// 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<DefaultBodyStability> {
self.default_body_stab_map.get(&def_id).copied()
}

pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
self.depr_map.get(&def_id).cloned()
}
@@ -416,19 +421,19 @@ 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: \
inspecting def_id={:?} span={:?} of stability={:?}",
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
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1094,6 +1094,11 @@ rustc_queries! {
separate_provide_extern
}

query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
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) }
}
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Original file line number Diff line number Diff line change
@@ -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,
19 changes: 14 additions & 5 deletions compiler/rustc_passes/src/lib_features.rs
Original file line number Diff line number Diff line change
@@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}

fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, 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));
}
21 changes: 17 additions & 4 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -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,
1 change: 1 addition & 0 deletions compiler/rustc_typeck/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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" }
27 changes: 22 additions & 5 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
@@ -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)) {
34 changes: 33 additions & 1 deletion compiler/rustc_typeck/src/check/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Symbol>,
issue: Option<NonZeroU32>,
) {
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>,
29 changes: 29 additions & 0 deletions src/test/ui/stability-attribute/auxiliary/default_body.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
19 changes: 19 additions & 0 deletions src/test/ui/stability-attribute/default-body-stability-err.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
38 changes: 38 additions & 0 deletions src/test/ui/stability-attribute/default-body-stability-err.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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
}
}
21 changes: 21 additions & 0 deletions src/test/ui/stability-attribute/default-body-stability-ok-impls.rs
Original file line number Diff line number Diff line change
@@ -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
}
}