Skip to content

Commit 33df6cc

Browse files
committed
EII lowering
1 parent 59d50cd commit 33df6cc

File tree

8 files changed

+232
-7
lines changed

8 files changed

+232
-7
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};
@@ -133,10 +134,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
133134
}
134135
}
135136

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

555+
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
556+
let res = self.resolver.get_partial_res(id)?;
557+
let Some(did) = res.expect_full_res().opt_def_id() else {
558+
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
559+
return None;
560+
};
561+
562+
Some(did)
563+
}
564+
472565
#[instrument(level = "debug", skip(self))]
473566
fn lower_use_tree(
474567
&mut self,

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -971,11 +971,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
971971
target_span: Span,
972972
target: Target,
973973
) -> &'hir [hir::Attribute] {
974-
if attrs.is_empty() {
974+
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
975+
}
976+
977+
fn lower_attrs_with_extra(
978+
&mut self,
979+
id: HirId,
980+
attrs: &[Attribute],
981+
target_span: Span,
982+
target: Target,
983+
extra_hir_attributes: &[hir::Attribute],
984+
) -> &'hir [hir::Attribute] {
985+
if attrs.is_empty() && extra_hir_attributes.is_empty() {
975986
&[]
976987
} else {
977-
let lowered_attrs =
988+
let mut lowered_attrs =
978989
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
990+
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
979991

980992
assert_eq!(id.owner, self.current_hir_id_owner);
981993
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
@@ -19,6 +19,23 @@ use crate::attrs::pretty_printing::PrintAttribute;
1919
use crate::limit::Limit;
2020
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
2121

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

712+
/// Implementation detail of `#[eii]`
713+
EiiExternTarget(EiiDecl),
714+
715+
/// Implementation detail of `#[eii]`
716+
EiiImpls(ThinVec<EiiImpl>),
717+
695718
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
696719
ExportName {
697720
/// 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
Doc(_) => Yes,
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
@@ -5,6 +5,7 @@ use rustc_ast::token::{CommentKind, DocFragmentKind};
55
use rustc_ast::{AttrStyle, IntTy, UintTy};
66
use rustc_ast_pretty::pp::Printer;
77
use rustc_data_structures::fx::FxIndexMap;
8+
use rustc_span::def_id::DefId;
89
use rustc_span::hygiene::Transparency;
910
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
1011
use rustc_target::spec::SanitizerSet;
@@ -170,4 +171,5 @@ print_debug!(
170171
DocFragmentKind,
171172
Transparency,
172173
SanitizerSet,
174+
DefId,
173175
);

compiler/rustc_passes/messages.ftl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,18 @@ passes_useless_stability =
590590
this stability annotation is useless
591591
.label = useless stability annotation
592592
.item = the stability attribute annotates this item
593+
594+
passes_eii_fn_with_target_feature =
595+
`#[{$name}]` is not allowed to have `#[target_feature]`
596+
.label = `#[{$name}]` is not allowed to have `#[target_feature]`
597+
598+
passes_eii_fn_with_track_caller =
599+
`#[{$name}]` is not allowed to have `#[track_caller]`
600+
.label = `#[{$name}]` is not allowed to have `#[track_caller]`
601+
602+
passes_eii_impl_not_function =
603+
`eii_macro_for` is only valid on functions
604+
605+
passes_eii_impl_requires_unsafe =
606+
`#[{$name}]` is unsafe to implement
607+
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`

compiler/rustc_passes/src/check_attr.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use rustc_feature::{
1919
BuiltinAttribute,
2020
};
2121
use rustc_hir::attrs::{
22-
AttributeKind, DocAttribute, DocInline, InlineAttr, MirDialect, MirPhase, ReprAttr,
23-
SanitizerSet,
22+
AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase,
23+
ReprAttr, SanitizerSet,
2424
};
2525
use rustc_hir::def::DefKind;
2626
use rustc_hir::def_id::LocalModDefId;
@@ -212,8 +212,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
212212
self.check_macro_export(hir_id, *span, target)
213213
},
214214
Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target),
215+
Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
216+
self.check_eii_impl(impls, target)
217+
},
215218
Attribute::Parsed(
216-
AttributeKind::BodyStability { .. }
219+
AttributeKind::EiiExternTarget { .. }
220+
| AttributeKind::BodyStability { .. }
217221
| AttributeKind::ConstStabilityIndirect
218222
| AttributeKind::MacroTransparency(_)
219223
| AttributeKind::Pointee(..)
@@ -459,6 +463,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
459463
);
460464
}
461465

466+
fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
467+
for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls {
468+
match target {
469+
Target::Fn => {}
470+
_ => {
471+
self.dcx().emit_err(errors::EiiImplNotFunction { span: *span });
472+
}
473+
}
474+
475+
if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe)
476+
&& !impl_marked_unsafe
477+
{
478+
self.dcx().emit_err(errors::EiiImplRequiresUnsafe {
479+
span: *span,
480+
name: self.tcx.item_name(*eii_macro),
481+
suggestion: errors::EiiImplRequiresUnsafeSuggestion {
482+
left: inner_span.shrink_to_lo(),
483+
right: inner_span.shrink_to_hi(),
484+
},
485+
});
486+
}
487+
}
488+
}
489+
462490
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no
463491
/// arguments.
464492
fn check_do_not_recommend(
@@ -684,6 +712,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
684712
sig_span: sig.span,
685713
});
686714
}
715+
716+
if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpls(impls) => impls) {
717+
let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
718+
for i in impls {
719+
self.dcx().emit_err(errors::EiiWithTrackCaller {
720+
attr_span,
721+
name: self.tcx.item_name(i.eii_macro),
722+
sig_span: sig.span,
723+
});
724+
}
725+
}
687726
}
688727
_ => {}
689728
}

compiler/rustc_passes/src/errors.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,3 +1305,42 @@ pub(crate) struct CustomMirIncompatibleDialectAndPhase {
13051305
#[label]
13061306
pub phase_span: Span,
13071307
}
1308+
1309+
#[derive(Diagnostic)]
1310+
#[diag(passes_eii_impl_not_function)]
1311+
pub(crate) struct EiiImplNotFunction {
1312+
#[primary_span]
1313+
pub span: Span,
1314+
}
1315+
1316+
#[derive(Diagnostic)]
1317+
#[diag(passes_eii_impl_requires_unsafe)]
1318+
pub(crate) struct EiiImplRequiresUnsafe {
1319+
#[primary_span]
1320+
pub span: Span,
1321+
pub name: Symbol,
1322+
#[subdiagnostic]
1323+
pub suggestion: EiiImplRequiresUnsafeSuggestion,
1324+
}
1325+
1326+
#[derive(Subdiagnostic)]
1327+
#[multipart_suggestion(
1328+
passes_eii_impl_requires_unsafe_suggestion,
1329+
applicability = "machine-applicable"
1330+
)]
1331+
pub(crate) struct EiiImplRequiresUnsafeSuggestion {
1332+
#[suggestion_part(code = "unsafe(")]
1333+
pub left: Span,
1334+
#[suggestion_part(code = ")")]
1335+
pub right: Span,
1336+
}
1337+
1338+
#[derive(Diagnostic)]
1339+
#[diag(passes_eii_fn_with_track_caller)]
1340+
pub(crate) struct EiiWithTrackCaller {
1341+
#[primary_span]
1342+
pub attr_span: Span,
1343+
pub name: Symbol,
1344+
#[label]
1345+
pub sig_span: Span,
1346+
}

0 commit comments

Comments
 (0)