Rollup merge of #92164 - WaffleLapkin:rustc_must_implement_one_of_attr, r=Aaron1011
Implement `#[rustc_must_implement_one_of]` attribute This PR adds a new attribute — `#[rustc_must_implement_one_of]` that allows changing the "minimal complete definition" of a trait. It's similar to GHC's minimal `{-# MINIMAL #-}` pragma, though `#[rustc_must_implement_one_of]` is weaker atm. Such attribute was long wanted. It can be, for example, used in `Read` trait to make transitions to recently added `read_buf` easier: ```rust #[rustc_must_implement_one_of(read, read_buf)] pub trait Read { fn read(&mut self, buf: &mut [u8]) -> Result<usize> { let mut buf = ReadBuf::new(buf); self.read_buf(&mut buf)?; Ok(buf.filled_len()) } fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { default_read_buf(|b| self.read(b), buf) } } impl Read for Ty0 {} //^ This will fail to compile even though all `Read` methods have default implementations // Both of these will compile just fine impl Read for Ty1 { fn read(&mut self, buf: &mut [u8]) -> Result<usize> { /* ... */ } } impl Read for Ty2 { fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { /* ... */ } } ``` For now, this is implemented as an internal attribute to start experimenting on the design of this feature. In the future we may want to extend it: - Allow arbitrary requirements like `a | (b & c)` - Allow multiple requirements like - ```rust #[rustc_must_implement_one_of(a, b)] #[rustc_must_implement_one_of(c, d)] ``` - Make it appear in rustdoc documentation - Change the syntax? - Etc Eventually, we should make an RFC and make this (or rather similar) attribute public. --- I'm fairly new to compiler development and not at all sure if the implementation makes sense, but at least it passes tests :)
This commit is contained in:
commit
32d85c0b5a
17 changed files with 431 additions and 4 deletions
|
@ -682,6 +682,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
||||||
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
||||||
),
|
),
|
||||||
|
rustc_attr!(
|
||||||
|
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing,
|
||||||
|
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
||||||
|
definition of a trait, it's currently in experimental form and should be changed before \
|
||||||
|
being exposed outside of the std"
|
||||||
|
),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes, Testing:
|
// Internal attributes, Testing:
|
||||||
|
|
|
@ -820,6 +820,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
data.skip_array_during_method_dispatch,
|
data.skip_array_during_method_dispatch,
|
||||||
data.specialization_kind,
|
data.specialization_kind,
|
||||||
self.def_path_hash(item_id),
|
self.def_path_hash(item_id),
|
||||||
|
data.must_implement_one_of,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
EntryKind::TraitAlias => ty::TraitDef::new(
|
EntryKind::TraitAlias => ty::TraitDef::new(
|
||||||
|
@ -831,6 +832,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
false,
|
false,
|
||||||
ty::trait_def::TraitSpecializationKind::None,
|
ty::trait_def::TraitSpecializationKind::None,
|
||||||
self.def_path_hash(item_id),
|
self.def_path_hash(item_id),
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
_ => bug!("def-index does not refer to trait or trait alias"),
|
_ => bug!("def-index does not refer to trait or trait alias"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1513,6 +1513,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
is_marker: trait_def.is_marker,
|
is_marker: trait_def.is_marker,
|
||||||
skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
|
skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
|
||||||
specialization_kind: trait_def.specialization_kind,
|
specialization_kind: trait_def.specialization_kind,
|
||||||
|
must_implement_one_of: trait_def.must_implement_one_of.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
EntryKind::Trait(self.lazy(data))
|
EntryKind::Trait(self.lazy(data))
|
||||||
|
|
|
@ -378,6 +378,7 @@ struct TraitData {
|
||||||
is_marker: bool,
|
is_marker: bool,
|
||||||
skip_array_during_method_dispatch: bool,
|
skip_array_during_method_dispatch: bool,
|
||||||
specialization_kind: ty::trait_def::TraitSpecializationKind,
|
specialization_kind: ty::trait_def::TraitSpecializationKind,
|
||||||
|
must_implement_one_of: Option<Box<[Ident]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(TyEncodable, TyDecodable)]
|
#[derive(TyEncodable, TyDecodable)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::traits::specialization_graph;
|
use crate::traits::specialization_graph;
|
||||||
use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
|
use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
|
||||||
use crate::ty::fold::TypeFoldable;
|
use crate::ty::fold::TypeFoldable;
|
||||||
use crate::ty::{Ty, TyCtxt};
|
use crate::ty::{Ident, Ty, TyCtxt};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::definitions::DefPathHash;
|
use rustc_hir::definitions::DefPathHash;
|
||||||
|
@ -44,6 +44,10 @@ pub struct TraitDef {
|
||||||
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
|
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
|
||||||
/// recomputed all the time.
|
/// recomputed all the time.
|
||||||
pub def_path_hash: DefPathHash,
|
pub def_path_hash: DefPathHash,
|
||||||
|
|
||||||
|
/// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
|
||||||
|
/// must be implemented.
|
||||||
|
pub must_implement_one_of: Option<Box<[Ident]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this trait is treated specially by the standard library
|
/// Whether this trait is treated specially by the standard library
|
||||||
|
@ -87,6 +91,7 @@ impl<'tcx> TraitDef {
|
||||||
skip_array_during_method_dispatch: bool,
|
skip_array_during_method_dispatch: bool,
|
||||||
specialization_kind: TraitSpecializationKind,
|
specialization_kind: TraitSpecializationKind,
|
||||||
def_path_hash: DefPathHash,
|
def_path_hash: DefPathHash,
|
||||||
|
must_implement_one_of: Option<Box<[Ident]>>,
|
||||||
) -> TraitDef {
|
) -> TraitDef {
|
||||||
TraitDef {
|
TraitDef {
|
||||||
def_id,
|
def_id,
|
||||||
|
@ -97,6 +102,7 @@ impl<'tcx> TraitDef {
|
||||||
skip_array_during_method_dispatch,
|
skip_array_during_method_dispatch,
|
||||||
specialization_kind,
|
specialization_kind,
|
||||||
def_path_hash,
|
def_path_hash,
|
||||||
|
must_implement_one_of,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1162,6 +1162,7 @@ symbols! {
|
||||||
rustc_macro_transparency,
|
rustc_macro_transparency,
|
||||||
rustc_main,
|
rustc_main,
|
||||||
rustc_mir,
|
rustc_mir,
|
||||||
|
rustc_must_implement_one_of,
|
||||||
rustc_nonnull_optimization_guaranteed,
|
rustc_nonnull_optimization_guaranteed,
|
||||||
rustc_object_lifetime_default,
|
rustc_object_lifetime_default,
|
||||||
rustc_on_unimplemented,
|
rustc_on_unimplemented,
|
||||||
|
|
|
@ -978,6 +978,10 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
||||||
// Check for missing items from trait
|
// Check for missing items from trait
|
||||||
let mut missing_items = Vec::new();
|
let mut missing_items = Vec::new();
|
||||||
|
|
||||||
|
let mut must_implement_one_of: Option<&[Ident]> =
|
||||||
|
trait_def.must_implement_one_of.as_deref();
|
||||||
|
|
||||||
for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
|
for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
|
||||||
let is_implemented = ancestors
|
let is_implemented = ancestors
|
||||||
.leaf_def(tcx, trait_item_id)
|
.leaf_def(tcx, trait_item_id)
|
||||||
|
@ -986,12 +990,37 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
|
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
|
||||||
missing_items.push(tcx.associated_item(trait_item_id));
|
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());
|
||||||
|
|
||||||
|
if is_implemented_here {
|
||||||
|
let trait_item = tcx.associated_item(trait_item_id);
|
||||||
|
if required_items.contains(&trait_item.ident) {
|
||||||
|
must_implement_one_of = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !missing_items.is_empty() {
|
if !missing_items.is_empty() {
|
||||||
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
|
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
|
||||||
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
|
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(missing_items) = must_implement_one_of {
|
||||||
|
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
|
||||||
|
let attr_span = tcx
|
||||||
|
.get_attrs(impl_trait_ref.def_id)
|
||||||
|
.iter()
|
||||||
|
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
|
||||||
|
.map(|attr| attr.span);
|
||||||
|
|
||||||
|
missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -637,6 +637,31 @@ fn missing_items_err(
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn missing_items_must_implement_one_of_err(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_span: Span,
|
||||||
|
missing_items: &[Ident],
|
||||||
|
annotation_span: Option<Span>,
|
||||||
|
) {
|
||||||
|
let missing_items_msg =
|
||||||
|
missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
|
||||||
|
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
impl_span,
|
||||||
|
E0046,
|
||||||
|
"not all trait items implemented, missing one of: `{}`",
|
||||||
|
missing_items_msg
|
||||||
|
);
|
||||||
|
err.span_label(impl_span, format!("missing one of `{}` in implementation", missing_items_msg));
|
||||||
|
|
||||||
|
if let Some(annotation_span) = annotation_span {
|
||||||
|
err.span_note(annotation_span, "required because of this annotation");
|
||||||
|
}
|
||||||
|
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
|
/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
|
||||||
fn bounds_from_generic_predicates<'tcx>(
|
fn bounds_from_generic_predicates<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
|
@ -1190,9 +1190,11 @@ fn super_predicates_that_define_assoc_type(
|
||||||
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
||||||
let item = tcx.hir().expect_item(def_id.expect_local());
|
let item = tcx.hir().expect_item(def_id.expect_local());
|
||||||
|
|
||||||
let (is_auto, unsafety) = match item.kind {
|
let (is_auto, unsafety, items) = match item.kind {
|
||||||
hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
|
hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
|
||||||
hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal),
|
(is_auto == hir::IsAuto::Yes, unsafety, items)
|
||||||
|
}
|
||||||
|
hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
|
||||||
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
|
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1219,6 +1221,103 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
||||||
ty::trait_def::TraitSpecializationKind::None
|
ty::trait_def::TraitSpecializationKind::None
|
||||||
};
|
};
|
||||||
let def_path_hash = tcx.def_path_hash(def_id);
|
let def_path_hash = tcx.def_path_hash(def_id);
|
||||||
|
|
||||||
|
let must_implement_one_of = tcx
|
||||||
|
.get_attrs(def_id)
|
||||||
|
.iter()
|
||||||
|
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
|
||||||
|
// Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
|
||||||
|
// and that they are all identifiers
|
||||||
|
.and_then(|attr| match attr.meta_item_list() {
|
||||||
|
Some(items) if items.len() < 2 => {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(
|
||||||
|
attr.span,
|
||||||
|
"the `#[rustc_must_implement_one_of]` attribute must be \
|
||||||
|
used with at least 2 args",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(items) => items
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.ident().ok_or(item.span()))
|
||||||
|
.collect::<Result<Box<[_]>, _>>()
|
||||||
|
.map_err(|span| {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(span, "must be a name of an associated function")
|
||||||
|
.emit();
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.zip(Some(attr.span)),
|
||||||
|
// Error is reported by `rustc_attr!`
|
||||||
|
None => None,
|
||||||
|
})
|
||||||
|
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
|
||||||
|
// functions in the trait with default implementations
|
||||||
|
.and_then(|(list, attr_span)| {
|
||||||
|
let errors = list.iter().filter_map(|ident| {
|
||||||
|
let item = items.iter().find(|item| item.ident == *ident);
|
||||||
|
|
||||||
|
match item {
|
||||||
|
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
|
||||||
|
if !item.defaultness.has_value() {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(
|
||||||
|
item.span,
|
||||||
|
"This function doesn't have a default implementation",
|
||||||
|
)
|
||||||
|
.span_note(attr_span, "required by this annotation")
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(item) => tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(item.span, "Not a function")
|
||||||
|
.span_note(attr_span, "required by this annotation")
|
||||||
|
.note(
|
||||||
|
"All `#[rustc_must_implement_one_of]` arguments \
|
||||||
|
must be associated function names",
|
||||||
|
)
|
||||||
|
.emit(),
|
||||||
|
None => tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(ident.span, "Function not found in this trait")
|
||||||
|
.emit(),
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
});
|
||||||
|
|
||||||
|
(errors.count() == 0).then_some(list)
|
||||||
|
})
|
||||||
|
// Check for duplicates
|
||||||
|
.and_then(|list| {
|
||||||
|
let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
|
||||||
|
let mut no_dups = true;
|
||||||
|
|
||||||
|
for ident in &*list {
|
||||||
|
if let Some(dup) = set.insert(ident.name, ident.span) {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
|
||||||
|
.note(
|
||||||
|
"All `#[rustc_must_implement_one_of]` arguments \
|
||||||
|
must be unique",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
no_dups = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
no_dups.then_some(list)
|
||||||
|
});
|
||||||
|
|
||||||
ty::TraitDef::new(
|
ty::TraitDef::new(
|
||||||
def_id,
|
def_id,
|
||||||
unsafety,
|
unsafety,
|
||||||
|
@ -1228,6 +1327,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
||||||
skip_array_during_method_dispatch,
|
skip_array_during_method_dispatch,
|
||||||
spec_kind,
|
spec_kind,
|
||||||
def_path_hash,
|
def_path_hash,
|
||||||
|
must_implement_one_of,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(eq, neq)]
|
||||||
|
trait Equal {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
!self.neq(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neq(&self, other: &Self) -> bool {
|
||||||
|
!self.eq(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T0;
|
||||||
|
struct T1;
|
||||||
|
struct T2;
|
||||||
|
struct T3;
|
||||||
|
|
||||||
|
impl Equal for T0 {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Equal for T1 {
|
||||||
|
fn neq(&self, _other: &Self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Equal for T2 {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neq(&self, _other: &Self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Equal for T3 {}
|
||||||
|
//~^ not all trait items implemented, missing one of: `eq`, `neq`
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0046]: not all trait items implemented, missing one of: `eq`, `neq`
|
||||||
|
--> $DIR/rustc_must_implement_one_of.rs:41:1
|
||||||
|
|
|
||||||
|
LL | impl Equal for T3 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation
|
||||||
|
|
|
||||||
|
note: required because of this annotation
|
||||||
|
--> $DIR/rustc_must_implement_one_of.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(eq, neq)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0046`.
|
|
@ -0,0 +1,19 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(a, a)]
|
||||||
|
//~^ Functions names are duplicated
|
||||||
|
trait Trait {
|
||||||
|
fn a() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(b, a, a, c, b, c)]
|
||||||
|
//~^ Functions names are duplicated
|
||||||
|
//~| Functions names are duplicated
|
||||||
|
//~| Functions names are duplicated
|
||||||
|
trait Trait1 {
|
||||||
|
fn a() {}
|
||||||
|
fn b() {}
|
||||||
|
fn c() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,34 @@
|
||||||
|
error: Functions names are duplicated
|
||||||
|
--> $DIR/rustc_must_implement_one_of_duplicates.rs:3:31
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, a)]
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be unique
|
||||||
|
|
||||||
|
error: Functions names are duplicated
|
||||||
|
--> $DIR/rustc_must_implement_one_of_duplicates.rs:9:34
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be unique
|
||||||
|
|
||||||
|
error: Functions names are duplicated
|
||||||
|
--> $DIR/rustc_must_implement_one_of_duplicates.rs:9:31
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be unique
|
||||||
|
|
||||||
|
error: Functions names are duplicated
|
||||||
|
--> $DIR/rustc_must_implement_one_of_duplicates.rs:9:40
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be unique
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#[rustc_must_implement_one_of(eq, neq)]
|
||||||
|
//~^ the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
|
||||||
|
trait Equal {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
!self.neq(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neq(&self, other: &Self) -> bool {
|
||||||
|
!self.eq(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
|
||||||
|
--> $DIR/rustc_must_implement_one_of_gated.rs:1:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(eq, neq)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -0,0 +1,38 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(a, b)]
|
||||||
|
//~^ Function not found in this trait
|
||||||
|
//~| Function not found in this trait
|
||||||
|
trait Tr0 {}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(a, b)]
|
||||||
|
//~^ Function not found in this trait
|
||||||
|
trait Tr1 {
|
||||||
|
fn a() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(a)]
|
||||||
|
//~^ the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
|
||||||
|
trait Tr2 {
|
||||||
|
fn a() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of]
|
||||||
|
//~^ malformed `rustc_must_implement_one_of` attribute input
|
||||||
|
trait Tr3 {}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(A, B)]
|
||||||
|
trait Tr4 {
|
||||||
|
const A: u8 = 1; //~ Not a function
|
||||||
|
|
||||||
|
type B; //~ Not a function
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_must_implement_one_of(a, b)]
|
||||||
|
trait Tr5 {
|
||||||
|
fn a(); //~ This function doesn't have a default implementation
|
||||||
|
|
||||||
|
fn b(); //~ This function doesn't have a default implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,82 @@
|
||||||
|
error: malformed `rustc_must_implement_one_of` attribute input
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:20:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
|
||||||
|
|
||||||
|
error: Function not found in this trait
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, b)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: Function not found in this trait
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, b)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: Function not found in this trait
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, b)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Not a function
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:26:5
|
||||||
|
|
|
||||||
|
LL | const A: u8 = 1;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: required by this annotation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(A, B)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
|
||||||
|
|
||||||
|
error: Not a function
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:28:5
|
||||||
|
|
|
||||||
|
LL | type B;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
note: required by this annotation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(A, B)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
|
||||||
|
|
||||||
|
error: This function doesn't have a default implementation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:33:5
|
||||||
|
|
|
||||||
|
LL | fn a();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
note: required by this annotation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, b)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: This function doesn't have a default implementation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:35:5
|
||||||
|
|
|
||||||
|
LL | fn b();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
note: required by this annotation
|
||||||
|
--> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_must_implement_one_of(a, b)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue