Skip to content
Open
Show file tree
Hide file tree
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
47 changes: 47 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_session::errors;

use super::prelude::*;
use super::util::parse_single_integer;
Expand All @@ -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 {
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,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;
Expand Down Expand Up @@ -215,6 +216,7 @@ attribute_parsers!(
Single<RustcLayoutScalarValidRangeStartParser>,
Single<RustcLegacyConstGenericsParser>,
Single<RustcLintOptDenyFieldAccessParser>,
Single<RustcMustImplementOneOfParser>,
Single<RustcObjectLifetimeDefaultParser>,
Single<RustcScalableVectorParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Expand Down Expand Up @@ -490,6 +492,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)
}
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_attr_parsing/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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())
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
ExpectedSingleArgument,
ExpectedList,
ExpectedListOrNoArgs,
ExpectedListWithNumArgsOrMore {
args: usize,
},
ExpectedNameValueOrNoArgs,
UnexpectedLiteral,
ExpectedNameValue(Option<Symbol>),
Expand Down Expand Up @@ -596,6 +599,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");
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,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,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ impl AttributeKind {
RustcLintQueryInstability => Yes,
RustcLintUntrackedQueryInformation => Yes,
RustcMain => No,
RustcMustImplementOneOf { .. } => No,
RustcNeverReturnsNullPointer => Yes,
RustcNoImplicitAutorefs => Yes,
RustcObjectLifetimeDefault => No,
Expand Down
18 changes: 0 additions & 18 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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}
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
86 changes: 8 additions & 78 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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(_));
Expand Down
60 changes: 0 additions & 60 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Loading
Loading