Skip to content

Commit 73ccfeb

Browse files
committed
Move check_rustc_must_implement_one_of validation to attribute parser
1 parent 88d9824 commit 73ccfeb

10 files changed

Lines changed: 249 additions & 133 deletions

File tree

‎compiler/rustc_ast_lowering/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ fn index_ast<'tcx>(
684684
mut_visit::walk_assoc_item(self, item, ctxt);
685685
match ctxt {
686686
visit::AssocCtxt::Trait => {
687-
self.replace_with_dummy(item, AssocItemKind::MacCall, AstOwner::TraitItem)
687+
self.insert(item.id, AstOwner::TraitItem(Box::new(item.clone())));
688688
}
689689
visit::AssocCtxt::Impl { .. } => {
690690
self.replace_with_dummy(item, AssocItemKind::MacCall, AstOwner::ImplItem)

‎compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs‎

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::path::PathBuf;
22

3-
use rustc_ast::{GenericParamKind, ItemKind, LitIntType, LitKind, MetaItemLit};
3+
use rustc_ast::{AssocItemKind, GenericParamKind, ItemKind, LitIntType, LitKind, MetaItemLit};
44
use rustc_attr_ir::lang_items::LangItem;
55
use rustc_attr_ir::{
66
BorrowckGraphvizFormatKind, CguFields, CguKind, RustcAssertVarianceKind, RustcCleanAttribute,
7-
RustcCleanQueries, RustcMirKind,
7+
RustcCleanQueries, RustcMirKind, find_attr,
88
};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_feature::AttributeStability;
@@ -86,6 +86,51 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser {
8686

8787
Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
8888
}
89+
90+
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
91+
if cx.target != Target::Trait {
92+
return;
93+
}
94+
95+
let item = cx.target_item.expect("missing AST target item for Target::Trait");
96+
let ItemKind::Trait(trait_) = &item.kind else {
97+
panic!("expected trait AST target item for Target::Trait");
98+
};
99+
100+
let fn_names =
101+
find_attr!(cx.parsed_attrs, RustcMustImplementOneOf { fn_names, .. } => fn_names)
102+
.expect("missing parsed RustcMustImplementOneOf attribute in finalize_check");
103+
104+
for ident in fn_names {
105+
let item = trait_.items.iter().find(|item| item.kind.ident() == Some(*ident));
106+
107+
match item {
108+
Some(item) => match &item.kind {
109+
AssocItemKind::Fn(f) => {
110+
if f.body.is_none() {
111+
cx.emit_err(diagnostics::FunctionNotHaveDefaultImplementation {
112+
span: item.span,
113+
note_span: attr_span,
114+
});
115+
}
116+
}
117+
AssocItemKind::Delegation(_) => {}
118+
_ => {
119+
cx.emit_err(diagnostics::MustImplementNotFunction {
120+
span: item.span,
121+
span_note: diagnostics::MustImplementNotFunctionSpanNote {
122+
span: attr_span,
123+
},
124+
note: diagnostics::MustImplementNotFunctionNote {},
125+
});
126+
}
127+
},
128+
None => {
129+
cx.emit_err(diagnostics::FunctionNotFoundInTrait { span: ident.span });
130+
}
131+
}
132+
}
133+
}
89134
}
90135

91136
pub(crate) struct RustcNeverReturnsNullPtrParser;

‎compiler/rustc_attr_parsing/src/diagnostics.rs‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,44 @@ pub(crate) struct FunctionNamesDuplicated {
111111
pub spans: Vec<Span>,
112112
}
113113

114+
#[derive(Diagnostic)]
115+
#[diag("function doesn't have a default implementation")]
116+
pub(crate) struct FunctionNotHaveDefaultImplementation {
117+
#[primary_span]
118+
pub span: Span,
119+
#[note("required by this annotation")]
120+
pub note_span: Span,
121+
}
122+
123+
#[derive(Diagnostic)]
124+
#[diag("not a function")]
125+
pub(crate) struct MustImplementNotFunction {
126+
#[primary_span]
127+
pub span: Span,
128+
#[subdiagnostic]
129+
pub span_note: MustImplementNotFunctionSpanNote,
130+
#[subdiagnostic]
131+
pub note: MustImplementNotFunctionNote,
132+
}
133+
134+
#[derive(Subdiagnostic)]
135+
#[note("required by this annotation")]
136+
pub(crate) struct MustImplementNotFunctionSpanNote {
137+
#[primary_span]
138+
pub span: Span,
139+
}
140+
141+
#[derive(Subdiagnostic)]
142+
#[note("all `#[rustc_must_implement_one_of]` arguments must be associated function names")]
143+
pub(crate) struct MustImplementNotFunctionNote {}
144+
145+
#[derive(Diagnostic)]
146+
#[diag("function not found in this trait")]
147+
pub(crate) struct FunctionNotFoundInTrait {
148+
#[primary_span]
149+
pub span: Span,
150+
}
151+
114152
#[derive(Diagnostic)]
115153
#[diag("unsafe attribute used without unsafe")]
116154
pub(crate) struct UnsafeAttrOutsideUnsafeLint {

‎compiler/rustc_passes/src/check_attr.rs‎

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_attr_ir::{
1717
OptimizeAttr, ReprAttr, RustcAssertVarianceKind, find_attr,
1818
};
1919
use rustc_attr_parsing::AttributeParser;
20-
use rustc_data_structures::thin_vec::ThinVec;
2120
use rustc_errors::{DiagCtxtHandle, IntoDiagArg};
2221
use rustc_feature::BUILTIN_ATTRIBUTE_SET;
2322
use rustc_hir::def::DefKind;
@@ -40,7 +39,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
4039
use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized, Variance};
4140
use rustc_session::diagnostics::feature_err;
4241
use rustc_span::edition::Edition;
43-
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym};
42+
use rustc_span::{DUMMY_SP, Span, Symbol, bug, kw, span_bug, sym};
4443
use rustc_structures::CrateType;
4544
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
4645
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
@@ -205,9 +204,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
205204
AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
206205
AttributeKind::Doc(attr) => self.check_doc_attrs(attr, hir_id, target),
207206
AttributeKind::EiiImpl(eii_impl) => self.check_eii_impl(eii_impl),
208-
AttributeKind::RustcMustImplementOneOf { attr_span, fn_names } => {
209-
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id, target)
210-
}
211207
AttributeKind::OnUnimplemented { directive } => {
212208
self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())
213209
}
@@ -363,6 +359,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
363359
AttributeKind::RustcMacroTransparency(_) => (),
364360
AttributeKind::RustcMain => (),
365361
AttributeKind::RustcMir(_) => (),
362+
AttributeKind::RustcMustImplementOneOf { .. } => (),
366363
AttributeKind::RustcMustMatchExhaustively(..) => (),
367364
AttributeKind::RustcNeverReturnsNullPtr => (),
368365
AttributeKind::RustcNoImplicitAutorefs => (),
@@ -460,56 +457,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
460457
})
461458
}
462459

463-
fn check_rustc_must_implement_one_of(
464-
&self,
465-
attr_span: Span,
466-
list: &ThinVec<Ident>,
467-
hir_id: HirId,
468-
target: Target,
469-
) {
470-
// Ignoring invalid targets because TyCtxt::associated_items emits bug if the target isn't valid
471-
// the parser has already produced an error for the target being invalid
472-
if !matches!(target, Target::Trait) {
473-
return;
474-
}
475-
476-
let def_id = hir_id.owner.def_id;
477-
478-
let items = self.tcx.associated_items(def_id);
479-
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
480-
// functions in the trait with default implementations
481-
for ident in list {
482-
let item = items
483-
.filter_by_name_unhygienic(ident.name)
484-
.find(|item| item.ident(self.tcx) == *ident);
485-
486-
match item {
487-
Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => {
488-
if !item.defaultness(self.tcx).has_value() {
489-
self.tcx.dcx().emit_err(
490-
diagnostics::FunctionNotHaveDefaultImplementation {
491-
span: self.tcx.def_span(item.def_id),
492-
note_span: attr_span,
493-
},
494-
);
495-
}
496-
}
497-
Some(item) => {
498-
self.dcx().emit_err(diagnostics::MustImplementNotFunction {
499-
span: self.tcx.def_span(item.def_id),
500-
span_note: diagnostics::MustImplementNotFunctionSpanNote {
501-
span: attr_span,
502-
},
503-
note: diagnostics::MustImplementNotFunctionNote {},
504-
});
505-
}
506-
None => {
507-
self.dcx().emit_err(diagnostics::FunctionNotFoundInTrait { span: ident.span });
508-
}
509-
}
510-
}
511-
}
512-
513460
/// Checks that each externally implementable item (EII) implementation uses `unsafe`
514461
/// exactly when its declaration requires it.
515462
fn check_eii_impl(&self, eii_impl: &EiiImpl) {

‎compiler/rustc_passes/src/diagnostics.rs‎

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -959,44 +959,6 @@ pub(crate) struct EiiWithoutImpl {
959959
pub help: (),
960960
}
961961

962-
#[derive(Diagnostic)]
963-
#[diag("function doesn't have a default implementation")]
964-
pub(crate) struct FunctionNotHaveDefaultImplementation {
965-
#[primary_span]
966-
pub span: Span,
967-
#[note("required by this annotation")]
968-
pub note_span: Span,
969-
}
970-
971-
#[derive(Diagnostic)]
972-
#[diag("not a function")]
973-
pub(crate) struct MustImplementNotFunction {
974-
#[primary_span]
975-
pub span: Span,
976-
#[subdiagnostic]
977-
pub span_note: MustImplementNotFunctionSpanNote,
978-
#[subdiagnostic]
979-
pub note: MustImplementNotFunctionNote,
980-
}
981-
982-
#[derive(Subdiagnostic)]
983-
#[note("required by this annotation")]
984-
pub(crate) struct MustImplementNotFunctionSpanNote {
985-
#[primary_span]
986-
pub span: Span,
987-
}
988-
989-
#[derive(Subdiagnostic)]
990-
#[note("all `#[rustc_must_implement_one_of]` arguments must be associated function names")]
991-
pub(crate) struct MustImplementNotFunctionNote {}
992-
993-
#[derive(Diagnostic)]
994-
#[diag("function not found in this trait")]
995-
pub(crate) struct FunctionNotFoundInTrait {
996-
#[primary_span]
997-
pub span: Span,
998-
}
999-
1000962
#[derive(Diagnostic)]
1001963
#[diag("there is no parameter `{$argument_name}` on trait `{$trait_name}`")]
1002964
pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
3+
#![feature(rustc_attrs)]
4+
#![feature(fn_delegation)]
5+
6+
mod to_reuse {
7+
pub fn b() {}
8+
pub fn c() {}
9+
}
10+
11+
#[rustc_must_implement_one_of(a, b)]
12+
trait TraitDelegation {
13+
fn a() {}
14+
reuse to_reuse::b;
15+
}
16+
17+
#[rustc_must_implement_one_of(a, ren)]
18+
trait TraitDelegationRenamed {
19+
fn a() {}
20+
reuse to_reuse::c as ren;
21+
}
22+
23+
fn main() {}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![feature(rustc_attrs)]
2+
3+
macro_rules! define_method {
4+
($name:ident) => {
5+
fn $name() {}
6+
};
7+
}
8+
9+
#[rustc_must_implement_one_of(a, b)]
10+
trait TraitMacro {
11+
fn a() {}
12+
define_method!(b);
13+
}
14+
15+
macro_rules! define_trait {
16+
($trait_name:ident, $m1:ident, $m2:ident) => {
17+
#[rustc_must_implement_one_of($m1, $m2)]
18+
trait $trait_name {
19+
fn $m1() {}
20+
fn $m2() {}
21+
}
22+
};
23+
}
24+
25+
define_trait!(TraitMacroWhole, foo, bar);
26+
27+
macro_rules! define_internal_b {
28+
() => {
29+
fn b() {}
30+
};
31+
}
32+
33+
#[rustc_must_implement_one_of(a, b)]
34+
//~^ ERROR function not found in this trait
35+
trait TraitHygiene {
36+
fn a() {}
37+
define_internal_b!();
38+
}
39+
40+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: function not found in this trait
2+
--> $DIR/rustc_must_implement_one_of_macros.rs:33:34
3+
|
4+
LL | #[rustc_must_implement_one_of(a, b)]
5+
| ^
6+
7+
error: aborting due to 1 previous error
8+

‎tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ trait TrTwoDefaults {
6565
fn c(); //~ ERROR function doesn't have a default implementation
6666
}
6767

68+
#[rustc_must_implement_one_of(a, b, C, D, missing)]
69+
//~^ ERROR function not found in this trait
70+
trait TrMixed {
71+
fn a() {}
72+
fn b(); //~ ERROR function doesn't have a default implementation
73+
const C: u8 = 1; //~ ERROR not a function
74+
type D; //~ ERROR not a function
75+
}
76+
6877
#[rustc_must_implement_one_of(abc, abc)]
6978
//~^ ERROR the `rustc_must_implement_one_of` attribute cannot be used on functions
7079
fn function() {}

0 commit comments

Comments
 (0)