Skip to content

Commit 9156bef

Browse files
committed
EII lowering
1 parent ceadaf8 commit 9156bef

File tree

8 files changed

+233
-6
lines changed

8 files changed

+233
-6
lines changed

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
22
use rustc_ast::visit::AssocCtxt;
33
use rustc_ast::*;
44
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
5-
use rustc_hir::attrs::AttributeKind;
5+
use rustc_hir::attrs::{AttributeKind, EiiDecl};
66
use rustc_hir::def::{DefKind, PerNS, Res};
77
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
88
use rustc_hir::{
@@ -11,6 +11,7 @@ use rustc_hir::{
1111
use rustc_index::{IndexSlice, IndexVec};
1212
use rustc_middle::span_bug;
1313
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
14+
use rustc_span::def_id::DefId;
1415
use rustc_span::edit_distance::find_best_match_for_name;
1516
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
1617
use smallvec::{SmallVec, smallvec};
@@ -135,10 +136,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
135136
}
136137
}
137138

139+
fn generate_extra_attrs_for_item_kind(
140+
&mut self,
141+
id: NodeId,
142+
i: &ItemKind,
143+
) -> Vec<hir::Attribute> {
144+
match i {
145+
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
146+
ItemKind::Fn(box Fn { eii_impls, .. }) => {
147+
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
148+
eii_impls
149+
.iter()
150+
.flat_map(
151+
|EiiImpl {
152+
node_id,
153+
eii_macro_path,
154+
impl_safety,
155+
span,
156+
inner_span,
157+
is_default,
158+
}| {
159+
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
160+
hir::attrs::EiiImpl {
161+
eii_macro: did,
162+
span: self.lower_span(*span),
163+
inner_span: self.lower_span(*inner_span),
164+
impl_marked_unsafe: self
165+
.lower_safety(*impl_safety, hir::Safety::Safe)
166+
.is_unsafe(),
167+
is_default: *is_default,
168+
}
169+
})
170+
},
171+
)
172+
.collect(),
173+
))]
174+
}
175+
ItemKind::MacroDef(
176+
_,
177+
MacroDef {
178+
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
179+
..
180+
},
181+
) => self
182+
.lower_path_simple_eii(id, extern_item_path)
183+
.map(|did| {
184+
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
185+
eii_extern_target: did,
186+
impl_unsafe: *impl_unsafe,
187+
span: self.lower_span(*span),
188+
}))]
189+
})
190+
.unwrap_or_default(),
191+
ItemKind::ExternCrate(..)
192+
| ItemKind::Use(..)
193+
| ItemKind::Static(..)
194+
| ItemKind::Const(..)
195+
| ItemKind::Mod(..)
196+
| ItemKind::ForeignMod(..)
197+
| ItemKind::GlobalAsm(..)
198+
| ItemKind::TyAlias(..)
199+
| ItemKind::Enum(..)
200+
| ItemKind::Struct(..)
201+
| ItemKind::Union(..)
202+
| ItemKind::Trait(..)
203+
| ItemKind::TraitAlias(..)
204+
| ItemKind::Impl(..)
205+
| ItemKind::MacCall(..)
206+
| ItemKind::MacroDef(..)
207+
| ItemKind::Delegation(..)
208+
| ItemKind::DelegationMac(..) => Vec::new(),
209+
}
210+
}
211+
138212
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
139213
let vis_span = self.lower_span(i.vis.span);
140214
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
141-
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i));
215+
216+
let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
217+
let attrs = self.lower_attrs_with_extra(
218+
hir_id,
219+
&i.attrs,
220+
i.span,
221+
Target::from_ast_item(i),
222+
&extra_hir_attributes,
223+
);
224+
142225
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
143226
let item = hir::Item {
144227
owner_id: hir_id.expect_owner(),
@@ -467,6 +550,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
467550
}
468551
}
469552

553+
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
554+
let res = self.resolver.get_partial_res(id)?;
555+
let Some(did) = res.expect_full_res().opt_def_id() else {
556+
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
557+
return None;
558+
};
559+
560+
Some(did)
561+
}
562+
470563
fn lower_const_item(
471564
&mut self,
472565
ty: &Ty,

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -945,11 +945,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
945945
target_span: Span,
946946
target: Target,
947947
) -> &'hir [hir::Attribute] {
948-
if attrs.is_empty() {
948+
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
949+
}
950+
951+
fn lower_attrs_with_extra(
952+
&mut self,
953+
id: HirId,
954+
attrs: &[Attribute],
955+
target_span: Span,
956+
target: Target,
957+
extra_hir_attributes: &[hir::Attribute],
958+
) -> &'hir [hir::Attribute] {
959+
if attrs.is_empty() && extra_hir_attributes.is_empty() {
949960
&[]
950961
} else {
951-
let lowered_attrs =
962+
let mut lowered_attrs =
952963
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
964+
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
953965

954966
assert_eq!(id.owner, self.current_hir_id_owner);
955967
let ret = self.arena.alloc_from_iter(lowered_attrs);

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ use crate::attrs::pretty_printing::PrintAttribute;
1717
use crate::limit::Limit;
1818
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
1919

20+
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
21+
pub struct EiiImpl {
22+
pub eii_macro: DefId,
23+
pub impl_marked_unsafe: bool,
24+
pub span: Span,
25+
pub inner_span: Span,
26+
pub is_default: bool,
27+
}
28+
29+
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
30+
pub struct EiiDecl {
31+
pub eii_extern_target: DefId,
32+
/// whether or not it is unsafe to implement this EII
33+
pub impl_unsafe: bool,
34+
pub span: Span,
35+
}
36+
2037
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
2138
pub enum InlineAttr {
2239
None,
@@ -522,6 +539,12 @@ pub enum AttributeKind {
522539
/// Represents `#[rustc_dummy]`.
523540
Dummy,
524541

542+
/// Implementation detail of `#[eii]`
543+
EiiExternTarget(EiiDecl),
544+
545+
/// Implementation detail of `#[eii]`
546+
EiiImpls(ThinVec<EiiImpl>),
547+
525548
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
526549
ExportName {
527550
/// The name to export this item with.

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ impl AttributeKind {
4343
DoNotImplementViaObject(..) => No,
4444
DocComment { .. } => Yes,
4545
Dummy => No,
46+
EiiExternTarget(_) => Yes,
47+
EiiImpls(..) => No,
4648
ExportName { .. } => Yes,
4749
ExportStable => No,
4850
FfiConst(..) => No,

compiler/rustc_hir/src/attrs/pretty_printing.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_abi::Align;
44
use rustc_ast::token::CommentKind;
55
use rustc_ast::{AttrStyle, IntTy, UintTy};
66
use rustc_ast_pretty::pp::Printer;
7+
use rustc_span::def_id::DefId;
78
use rustc_span::hygiene::Transparency;
89
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
910
use rustc_target::spec::SanitizerSet;
@@ -159,4 +160,5 @@ print_debug!(
159160
CommentKind,
160161
Transparency,
161162
SanitizerSet,
163+
DefId,
162164
);

compiler/rustc_passes/messages.ftl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,3 +705,18 @@ passes_useless_stability =
705705
this stability annotation is useless
706706
.label = useless stability annotation
707707
.item = the stability attribute annotates this item
708+
709+
passes_eii_fn_with_target_feature =
710+
`#[{$name}]` is not allowed to have `#[target_feature]`
711+
.label = `#[{$name}]` is not allowed to have `#[target_feature]`
712+
713+
passes_eii_fn_with_track_caller =
714+
`#[{$name}]` is not allowed to have `#[track_caller]`
715+
.label = `#[{$name}]` is not allowed to have `#[track_caller]`
716+
717+
passes_eii_impl_not_function =
718+
`eii_macro_for` is only valid on functions
719+
720+
passes_eii_impl_requires_unsafe =
721+
`#[{$name}]` is unsafe to implement
722+
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`

compiler/rustc_passes/src/check_attr.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use rustc_feature::{
1818
ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
1919
BuiltinAttribute,
2020
};
21-
use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet};
21+
use rustc_hir::attrs::{
22+
AttributeKind, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet,
23+
};
2224
use rustc_hir::def::DefKind;
2325
use rustc_hir::def_id::LocalModDefId;
2426
use rustc_hir::intravisit::{self, Visitor};
@@ -221,8 +223,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
221223
Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
222224
self.check_macro_export(hir_id, *span, target)
223225
},
226+
Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
227+
self.check_eii_impl(impls, target)
228+
},
224229
Attribute::Parsed(
225-
AttributeKind::BodyStability { .. }
230+
AttributeKind::EiiExternTarget { .. }
231+
| AttributeKind::BodyStability { .. }
226232
| AttributeKind::ConstStabilityIndirect
227233
| AttributeKind::MacroTransparency(_)
228234
| AttributeKind::Pointee(..)
@@ -461,6 +467,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
461467
);
462468
}
463469

470+
fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
471+
for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls {
472+
match target {
473+
Target::Fn => {}
474+
_ => {
475+
self.dcx().emit_err(errors::EiiImplNotFunction { span: *span });
476+
}
477+
}
478+
479+
if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe)
480+
&& !impl_marked_unsafe
481+
{
482+
self.dcx().emit_err(errors::EiiImplRequiresUnsafe {
483+
span: *span,
484+
name: self.tcx.item_name(*eii_macro),
485+
suggestion: errors::EiiImplRequiresUnsafeSuggestion {
486+
left: inner_span.shrink_to_lo(),
487+
right: inner_span.shrink_to_hi(),
488+
},
489+
});
490+
}
491+
}
492+
}
493+
464494
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no
465495
/// arguments.
466496
fn check_do_not_recommend(
@@ -660,6 +690,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
660690
sig_span: sig.span,
661691
});
662692
}
693+
694+
if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpls(impls) => impls) {
695+
let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
696+
for i in impls {
697+
self.dcx().emit_err(errors::EiiWithTrackCaller {
698+
attr_span,
699+
name: self.tcx.item_name(i.eii_macro),
700+
sig_span: sig.span,
701+
});
702+
}
703+
}
663704
}
664705
_ => {}
665706
}

compiler/rustc_passes/src/errors.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,3 +1629,42 @@ pub(crate) struct CustomMirIncompatibleDialectAndPhase {
16291629
#[label]
16301630
pub phase_span: Span,
16311631
}
1632+
1633+
#[derive(Diagnostic)]
1634+
#[diag(passes_eii_impl_not_function)]
1635+
pub(crate) struct EiiImplNotFunction {
1636+
#[primary_span]
1637+
pub span: Span,
1638+
}
1639+
1640+
#[derive(Diagnostic)]
1641+
#[diag(passes_eii_impl_requires_unsafe)]
1642+
pub(crate) struct EiiImplRequiresUnsafe {
1643+
#[primary_span]
1644+
pub span: Span,
1645+
pub name: Symbol,
1646+
#[subdiagnostic]
1647+
pub suggestion: EiiImplRequiresUnsafeSuggestion,
1648+
}
1649+
1650+
#[derive(Subdiagnostic)]
1651+
#[multipart_suggestion(
1652+
passes_eii_impl_requires_unsafe_suggestion,
1653+
applicability = "machine-applicable"
1654+
)]
1655+
pub(crate) struct EiiImplRequiresUnsafeSuggestion {
1656+
#[suggestion_part(code = "unsafe(")]
1657+
pub left: Span,
1658+
#[suggestion_part(code = ")")]
1659+
pub right: Span,
1660+
}
1661+
1662+
#[derive(Diagnostic)]
1663+
#[diag(passes_eii_fn_with_track_caller)]
1664+
pub(crate) struct EiiWithTrackCaller {
1665+
#[primary_span]
1666+
pub attr_span: Span,
1667+
pub name: Symbol,
1668+
#[label]
1669+
pub sig_span: Span,
1670+
}

0 commit comments

Comments
 (0)