Rollup merge of #150236 - Bryntet:parse_rustc_must_impl, r=JonathanBrouwer
Port `#[rustc_must_implement_one_of]` to attribute parser Stumbled upon a weird (bug ?) behaviour while making this PR it seems like it is possible to reach `check_attr.rs` checks without the attribute allowed target checks having already been finished, I added a comment about how to reproduce this in `check_attr.rs` otherwise good to note is that a bunch of code was moved from `compiler/rustc_hir_analysis/src/collect.rs` to `check_attr.rs` r? `@JonathanBrouwer`
This commit is contained in:
commit
096bb5b615
17 changed files with 244 additions and 206 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
||||
use rustc_session::errors;
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
|
|
@ -13,6 +14,52 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcMustImplementOneOfParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fn_names = ThinVec::new();
|
||||
|
||||
let inputs: Vec<_> = list.mixed().collect();
|
||||
|
||||
if inputs.len() < 2 {
|
||||
cx.expected_list_with_num_args_or_more(2, list.span);
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut errored = false;
|
||||
for argument in inputs {
|
||||
let Some(meta) = argument.meta_item() else {
|
||||
cx.expected_identifier(argument.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(ident) = meta.ident() else {
|
||||
cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
|
||||
errored = true;
|
||||
continue;
|
||||
};
|
||||
|
||||
fn_names.push(ident);
|
||||
}
|
||||
if errored {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNeverReturnsNullPointerParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,9 @@ use crate::attributes::rustc_internal::{
|
|||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
|
||||
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
|
||||
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
|
|
@ -217,6 +218,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcMustImplementOneOfParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
|
|
@ -492,6 +494,17 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list_with_num_args_or_more(
|
||||
&self,
|
||||
args: usize,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use std::fmt::{Debug, Display};
|
|||
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp};
|
||||
use rustc_ast::{
|
||||
AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Diag, PResult};
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
|
|
@ -256,6 +258,11 @@ impl Debug for MetaItemParser {
|
|||
}
|
||||
|
||||
impl MetaItemParser {
|
||||
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
if let Some(other) = self.args.span() {
|
||||
self.path.borrow().span().with_hi(other.hi())
|
||||
|
|
|
|||
|
|
@ -520,6 +520,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
|||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
ExpectedListOrNoArgs,
|
||||
ExpectedListWithNumArgsOrMore {
|
||||
args: usize,
|
||||
},
|
||||
ExpectedNameValueOrNoArgs,
|
||||
ExpectedNonEmptyStringLiteral,
|
||||
UnexpectedLiteral,
|
||||
|
|
@ -597,6 +600,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
AttributeParseErrorReason::ExpectedListOrNoArgs => {
|
||||
diag.span_label(self.span, "expected a list or no arguments here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args } => {
|
||||
diag.span_label(self.span, format!("expected {args} or more items"));
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedNameValueOrNoArgs => {
|
||||
diag.span_label(self.span, "didn't expect a list here");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -952,6 +952,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_main]`.
|
||||
RustcMain,
|
||||
|
||||
/// Represents `#[rustc_must_implement_one_of]`
|
||||
RustcMustImplementOneOf { attr_span: Span, fn_names: ThinVec<Ident> },
|
||||
|
||||
/// Represents `#[rustc_never_returns_null_ptr]`
|
||||
RustcNeverReturnsNullPointer,
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ impl AttributeKind {
|
|||
RustcLintQueryInstability => Yes,
|
||||
RustcLintUntrackedQueryInformation => Yes,
|
||||
RustcMain => No,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
|
|
|
|||
|
|
@ -208,14 +208,6 @@ hir_analysis_field_already_declared_previous_nested =
|
|||
.previous_decl_label = `{$field_name}` first declared here in this unnamed field
|
||||
.previous_nested_field_decl_note = field `{$field_name}` first declared here
|
||||
|
||||
hir_analysis_function_not_found_in_trait = function not found in this trait
|
||||
|
||||
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
|
||||
.note = required by this annotation
|
||||
|
||||
hir_analysis_functions_names_duplicated = functions names are duplicated
|
||||
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
|
||||
|
||||
hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl
|
||||
|
||||
hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
|
|
@ -381,16 +373,6 @@ hir_analysis_missing_type_params =
|
|||
*[other] parameters
|
||||
} must be specified on the object type
|
||||
|
||||
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
|
||||
|
||||
hir_analysis_must_implement_not_function = not a function
|
||||
|
||||
hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
|
||||
|
||||
hir_analysis_must_implement_not_function_span_note = required by this annotation
|
||||
|
||||
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
|
||||
|
||||
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
|
||||
|
||||
hir_analysis_not_supported_delegation = {$descr}
|
||||
|
|
|
|||
|
|
@ -1340,9 +1340,7 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
}
|
||||
|
||||
if let Some(missing_items) = must_implement_one_of {
|
||||
let attr_span = tcx
|
||||
.get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of)
|
||||
.map(|attr| attr.span());
|
||||
let attr_span = find_attr!(tcx.get_all_attrs(trait_ref.def_id), AttributeKind::RustcMustImplementOneOf {attr_span, ..} => *attr_span);
|
||||
|
||||
missing_items_must_implement_one_of_err(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use std::ops::Bound;
|
|||
use rustc_abi::{ExternAbi, Size};
|
||||
use rustc_ast::Recovered;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
|
||||
};
|
||||
|
|
@ -916,84 +915,15 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
} else {
|
||||
ty::trait_def::TraitSpecializationKind::None
|
||||
};
|
||||
let must_implement_one_of = attrs
|
||||
.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.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() });
|
||||
|
||||
None
|
||||
}
|
||||
Some(items) => items
|
||||
.into_iter()
|
||||
.map(|item| item.ident().ok_or(item.span()))
|
||||
.collect::<Result<Box<[_]>, _>>()
|
||||
.map_err(|span| {
|
||||
tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span });
|
||||
})
|
||||
.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 = tcx
|
||||
.associated_items(def_id)
|
||||
.filter_by_name_unhygienic(ident.name)
|
||||
.find(|item| item.ident(tcx) == *ident);
|
||||
|
||||
match item {
|
||||
Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => {
|
||||
if !item.defaultness(tcx).has_value() {
|
||||
tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation {
|
||||
span: tcx.def_span(item.def_id),
|
||||
note_span: attr_span,
|
||||
});
|
||||
|
||||
return Some(());
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
Some(item) => {
|
||||
tcx.dcx().emit_err(errors::MustImplementNotFunction {
|
||||
span: tcx.def_span(item.def_id),
|
||||
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
|
||||
note: errors::MustImplementNotFunctionNote {},
|
||||
});
|
||||
}
|
||||
None => {
|
||||
tcx.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
});
|
||||
|
||||
(errors.count() == 0).then_some(list)
|
||||
})
|
||||
// Check for duplicates
|
||||
.and_then(|list| {
|
||||
let mut set: UnordMap<Symbol, Span> = Default::default();
|
||||
let mut no_dups = true;
|
||||
|
||||
for ident in &*list {
|
||||
if let Some(dup) = set.insert(ident.name, ident.span) {
|
||||
tcx.dcx()
|
||||
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
|
||||
|
||||
no_dups = false;
|
||||
}
|
||||
}
|
||||
|
||||
no_dups.then_some(list)
|
||||
});
|
||||
let must_implement_one_of = find_attr!(
|
||||
attrs,
|
||||
AttributeKind::RustcMustImplementOneOf { fn_names, .. } =>
|
||||
fn_names
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Box<[_]>>()
|
||||
);
|
||||
|
||||
let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
|
||||
let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_));
|
||||
|
|
|
|||
|
|
@ -741,66 +741,6 @@ pub(crate) struct ParenSugarAttribute {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_must_implement_one_of_attribute)]
|
||||
pub(crate) struct MustImplementOneOfAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_must_be_name_of_associated_function)]
|
||||
pub(crate) struct MustBeNameOfAssociatedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_function_not_have_default_implementation)]
|
||||
pub(crate) struct FunctionNotHaveDefaultImplementation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub note_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_must_implement_not_function)]
|
||||
pub(crate) struct MustImplementNotFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub span_note: MustImplementNotFunctionSpanNote,
|
||||
#[subdiagnostic]
|
||||
pub note: MustImplementNotFunctionNote,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(hir_analysis_must_implement_not_function_span_note)]
|
||||
pub(crate) struct MustImplementNotFunctionSpanNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(hir_analysis_must_implement_not_function_note)]
|
||||
pub(crate) struct MustImplementNotFunctionNote {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_function_not_found_in_trait)]
|
||||
pub(crate) struct FunctionNotFoundInTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_functions_names_duplicated)]
|
||||
#[note]
|
||||
pub(crate) struct FunctionNamesDuplicated {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_simd_ffi_highly_experimental)]
|
||||
#[help]
|
||||
|
|
|
|||
|
|
@ -236,6 +236,14 @@ passes_feature_previously_declared =
|
|||
passes_feature_stable_twice =
|
||||
feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
|
||||
|
||||
passes_function_not_found_in_trait = function not found in this trait
|
||||
|
||||
passes_function_not_have_default_implementation = function doesn't have a default implementation
|
||||
.note = required by this annotation
|
||||
|
||||
passes_functions_names_duplicated = functions names are duplicated
|
||||
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
|
||||
|
||||
passes_has_incoherent_inherent_impl =
|
||||
`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits
|
||||
.label = only adts, extern types and traits are supported
|
||||
|
|
@ -370,6 +378,12 @@ passes_multiple_rustc_main =
|
|||
.first = first `#[rustc_main]` function
|
||||
.additional = additional `#[rustc_main]` function
|
||||
|
||||
passes_must_implement_not_function = not a function
|
||||
|
||||
passes_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
|
||||
|
||||
passes_must_implement_not_function_span_note = required by this annotation
|
||||
|
||||
passes_must_not_suspend =
|
||||
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
|
||||
.label = is not a struct, enum, union, or trait
|
||||
|
|
@ -484,10 +498,6 @@ passes_sanitize_attribute_not_allowed =
|
|||
.no_body = function has no body
|
||||
.help = sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
passes_should_be_applied_to_trait =
|
||||
attribute should be applied to a trait
|
||||
.label = not a trait
|
||||
|
||||
passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait
|
||||
passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable...
|
||||
passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable...
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_ast::{AttrStyle, MetaItemKind, ast};
|
|||
use rustc_attr_parsing::{AttributeParser, Late};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
|
||||
use rustc_feature::{
|
||||
ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
|
||||
|
|
@ -47,7 +48,7 @@ use rustc_session::lint::builtin::{
|
|||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
|
@ -219,6 +220,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
|
||||
self.check_eii_impl(impls, target)
|
||||
},
|
||||
Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => {
|
||||
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target)
|
||||
},
|
||||
Attribute::Parsed(
|
||||
AttributeKind::EiiExternTarget { .. }
|
||||
| AttributeKind::EiiExternItem
|
||||
|
|
@ -316,7 +320,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| [sym::rustc_dirty, ..]
|
||||
| [sym::rustc_if_this_changed, ..]
|
||||
| [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
|
||||
[sym::rustc_must_implement_one_of, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
|
||||
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
|
||||
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
|
||||
[sym::rustc_has_incoherent_inherent_impls, ..] => {
|
||||
|
|
@ -445,6 +448,63 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_mix_no_mangle_export(hir_id, attrs);
|
||||
}
|
||||
|
||||
fn check_rustc_must_implement_one_of(
|
||||
&self,
|
||||
attr_span: Span,
|
||||
list: &ThinVec<Ident>,
|
||||
hir_id: HirId,
|
||||
target: Target,
|
||||
) {
|
||||
// Ignoring invalid targets because TyCtxt::associated_items emits bug if the target isn't valid
|
||||
// the parser has already produced an error for the target being invalid
|
||||
if !matches!(target, Target::Trait) {
|
||||
return;
|
||||
}
|
||||
|
||||
let def_id = hir_id.owner.def_id;
|
||||
|
||||
let items = self.tcx.associated_items(def_id);
|
||||
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
|
||||
// functions in the trait with default implementations
|
||||
for ident in list {
|
||||
let item = items
|
||||
.filter_by_name_unhygienic(ident.name)
|
||||
.find(|item| item.ident(self.tcx) == *ident);
|
||||
|
||||
match item {
|
||||
Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => {
|
||||
if !item.defaultness(self.tcx).has_value() {
|
||||
self.tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation {
|
||||
span: self.tcx.def_span(item.def_id),
|
||||
note_span: attr_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(item) => {
|
||||
self.dcx().emit_err(errors::MustImplementNotFunction {
|
||||
span: self.tcx.def_span(item.def_id),
|
||||
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
|
||||
note: errors::MustImplementNotFunctionNote {},
|
||||
});
|
||||
}
|
||||
None => {
|
||||
self.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for duplicates
|
||||
|
||||
let mut set: UnordMap<Symbol, Span> = Default::default();
|
||||
|
||||
for ident in &*list {
|
||||
if let Some(dup) = set.insert(ident.name, ident.span) {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
|
||||
for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls {
|
||||
match target {
|
||||
|
|
@ -1221,16 +1281,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the attribute is applied to a trait.
|
||||
fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) {
|
||||
match target {
|
||||
Target::Trait => {}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the `#[repr]` attributes on `item` are valid.
|
||||
fn check_repr(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -89,15 +89,6 @@ pub(crate) struct NonExhaustiveWithDefaultFieldValues {
|
|||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_should_be_applied_to_trait)]
|
||||
pub(crate) struct AttrShouldBeAppliedToTrait {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_alias_bad_location)]
|
||||
pub(crate) struct DocAliasBadLocation<'a> {
|
||||
|
|
@ -1323,3 +1314,49 @@ pub(crate) struct DuplicateEiiImpls {
|
|||
#[help]
|
||||
pub help: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_function_not_have_default_implementation)]
|
||||
pub(crate) struct FunctionNotHaveDefaultImplementation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note]
|
||||
pub note_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_must_implement_not_function)]
|
||||
pub(crate) struct MustImplementNotFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub span_note: MustImplementNotFunctionSpanNote,
|
||||
#[subdiagnostic]
|
||||
pub note: MustImplementNotFunctionNote,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(passes_must_implement_not_function_span_note)]
|
||||
pub(crate) struct MustImplementNotFunctionSpanNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(passes_must_implement_not_function_note)]
|
||||
pub(crate) struct MustImplementNotFunctionNote {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_function_not_found_in_trait)]
|
||||
pub(crate) struct FunctionNotFoundInTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_functions_names_duplicated)]
|
||||
#[note]
|
||||
pub(crate) struct FunctionNamesDuplicated {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number liter
|
|||
|
||||
session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
|
||||
|
||||
session_must_be_name_of_associated_function = must be a name of an associated function
|
||||
|
||||
session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
|
||||
|
||||
session_not_supported = not supported
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@ pub(crate) struct CliFeatureDiagnosticHelp {
|
|||
pub(crate) feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_must_be_name_of_associated_function)]
|
||||
pub struct MustBeNameOfAssociatedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_not_circumvent_feature)]
|
||||
pub(crate) struct NotCircumventFeature;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ trait Tr1 {
|
|||
}
|
||||
|
||||
#[rustc_must_implement_one_of(a)]
|
||||
//~^ ERROR the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
|
||||
//~^ ERROR malformed
|
||||
trait Tr2 {
|
||||
fn a() {}
|
||||
}
|
||||
|
|
@ -36,11 +36,11 @@ trait Tr5 {
|
|||
}
|
||||
|
||||
#[rustc_must_implement_one_of(abc, xyz)]
|
||||
//~^ ERROR attribute should be applied to a trait
|
||||
//~^ ERROR `#[rustc_must_implement_one_of]` attribute cannot be used on functions
|
||||
fn function() {}
|
||||
|
||||
#[rustc_must_implement_one_of(abc, xyz)]
|
||||
//~^ ERROR attribute should be applied to a trait
|
||||
//~^ ERROR `#[rustc_must_implement_one_of]` attribute cannot be used on structs
|
||||
struct Struct {}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
error: malformed `rustc_must_implement_one_of` attribute input
|
||||
error[E0539]: malformed `rustc_must_implement_one_of` attribute input
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(a)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^
|
||||
| | |
|
||||
| | expected 2 or more items
|
||||
| help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
|
||||
|
||||
error[E0539]: 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, ...)]`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected this to be a list
|
||||
| help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
|
||||
|
||||
error: attribute should be applied to a trait
|
||||
error: `#[rustc_must_implement_one_of]` attribute cannot be used on functions
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:38:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(abc, xyz)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | fn function() {}
|
||||
| ---------------- not a trait
|
||||
|
|
||||
= help: `#[rustc_must_implement_one_of]` can only be applied to traits
|
||||
|
||||
error: attribute should be applied to a trait
|
||||
error: `#[rustc_must_implement_one_of]` attribute cannot be used on structs
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:42:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(abc, xyz)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | struct Struct {}
|
||||
| ---------------- not a trait
|
||||
|
|
||||
= help: `#[rustc_must_implement_one_of]` can only be applied to traits
|
||||
|
||||
error: function not found in this trait
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
|
||||
|
|
@ -40,12 +50,6 @@ error: function not found in this trait
|
|||
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
|
||||
|
|
||||
|
|
@ -98,3 +102,4 @@ LL | #[rustc_must_implement_one_of(a, b)]
|
|||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue