EII lowering
This commit is contained in:
parent
59d50cd2ad
commit
33df6ccb21
8 changed files with 232 additions and 7 deletions
|
|
@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{
|
||||
|
|
@ -11,6 +11,7 @@ use rustc_hir::{
|
|||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
|
@ -133,10 +134,92 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_extra_attrs_for_item_kind(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
i: &ItemKind,
|
||||
) -> Vec<hir::Attribute> {
|
||||
match i {
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) => {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
|
||||
eii_impls
|
||||
.iter()
|
||||
.flat_map(
|
||||
|EiiImpl {
|
||||
node_id,
|
||||
eii_macro_path,
|
||||
impl_safety,
|
||||
span,
|
||||
inner_span,
|
||||
is_default,
|
||||
}| {
|
||||
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
|
||||
hir::attrs::EiiImpl {
|
||||
eii_macro: did,
|
||||
span: self.lower_span(*span),
|
||||
inner_span: self.lower_span(*inner_span),
|
||||
impl_marked_unsafe: self
|
||||
.lower_safety(*impl_safety, hir::Safety::Safe)
|
||||
.is_unsafe(),
|
||||
is_default: *is_default,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
))]
|
||||
}
|
||||
ItemKind::MacroDef(
|
||||
_,
|
||||
MacroDef {
|
||||
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
|
||||
..
|
||||
},
|
||||
) => self
|
||||
.lower_path_simple_eii(id, extern_item_path)
|
||||
.map(|did| {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
|
||||
eii_extern_target: did,
|
||||
impl_unsafe: *impl_unsafe,
|
||||
span: self.lower_span(*span),
|
||||
}))]
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::GlobalAsm(..)
|
||||
| ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::TraitAlias(..)
|
||||
| ItemKind::Impl(..)
|
||||
| ItemKind::MacCall(..)
|
||||
| ItemKind::MacroDef(..)
|
||||
| ItemKind::Delegation(..)
|
||||
| ItemKind::DelegationMac(..) => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
||||
let vis_span = self.lower_span(i.vis.span);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i));
|
||||
|
||||
let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
|
||||
let attrs = self.lower_attrs_with_extra(
|
||||
hir_id,
|
||||
&i.attrs,
|
||||
i.span,
|
||||
Target::from_ast_item(i),
|
||||
&extra_hir_attributes,
|
||||
);
|
||||
|
||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
|
||||
let item = hir::Item {
|
||||
owner_id: hir_id.expect_owner(),
|
||||
|
|
@ -469,6 +552,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
|
||||
let res = self.resolver.get_partial_res(id)?;
|
||||
let Some(did) = res.expect_full_res().opt_def_id() else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(did)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_use_tree(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -971,11 +971,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
target_span: Span,
|
||||
target: Target,
|
||||
) -> &'hir [hir::Attribute] {
|
||||
if attrs.is_empty() {
|
||||
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
|
||||
}
|
||||
|
||||
fn lower_attrs_with_extra(
|
||||
&mut self,
|
||||
id: HirId,
|
||||
attrs: &[Attribute],
|
||||
target_span: Span,
|
||||
target: Target,
|
||||
extra_hir_attributes: &[hir::Attribute],
|
||||
) -> &'hir [hir::Attribute] {
|
||||
if attrs.is_empty() && extra_hir_attributes.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
let lowered_attrs =
|
||||
let mut lowered_attrs =
|
||||
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
|
||||
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
|
||||
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,23 @@ use crate::attrs::pretty_printing::PrintAttribute;
|
|||
use crate::limit::Limit;
|
||||
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub struct EiiImpl {
|
||||
pub eii_macro: DefId,
|
||||
pub impl_marked_unsafe: bool,
|
||||
pub span: Span,
|
||||
pub inner_span: Span,
|
||||
pub is_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub struct EiiDecl {
|
||||
pub eii_extern_target: DefId,
|
||||
/// whether or not it is unsafe to implement this EII
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum InlineAttr {
|
||||
None,
|
||||
|
|
@ -692,6 +709,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_dummy]`.
|
||||
Dummy,
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiExternTarget(EiiDecl),
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiImpls(ThinVec<EiiImpl>),
|
||||
|
||||
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
|
||||
ExportName {
|
||||
/// The name to export this item with.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ impl AttributeKind {
|
|||
Doc(_) => Yes,
|
||||
DocComment { .. } => Yes,
|
||||
Dummy => No,
|
||||
EiiExternTarget(_) => Yes,
|
||||
EiiImpls(..) => No,
|
||||
ExportName { .. } => Yes,
|
||||
ExportStable => No,
|
||||
FfiConst(..) => No,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_ast::token::{CommentKind, DocFragmentKind};
|
|||
use rustc_ast::{AttrStyle, IntTy, UintTy};
|
||||
use rustc_ast_pretty::pp::Printer;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
|
@ -170,4 +171,5 @@ print_debug!(
|
|||
DocFragmentKind,
|
||||
Transparency,
|
||||
SanitizerSet,
|
||||
DefId,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -590,3 +590,18 @@ passes_useless_stability =
|
|||
this stability annotation is useless
|
||||
.label = useless stability annotation
|
||||
.item = the stability attribute annotates this item
|
||||
|
||||
passes_eii_fn_with_target_feature =
|
||||
`#[{$name}]` is not allowed to have `#[target_feature]`
|
||||
.label = `#[{$name}]` is not allowed to have `#[target_feature]`
|
||||
|
||||
passes_eii_fn_with_track_caller =
|
||||
`#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
.label = `#[{$name}]` is not allowed to have `#[track_caller]`
|
||||
|
||||
passes_eii_impl_not_function =
|
||||
`eii_macro_for` is only valid on functions
|
||||
|
||||
passes_eii_impl_requires_unsafe =
|
||||
`#[{$name}]` is unsafe to implement
|
||||
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ use rustc_feature::{
|
|||
BuiltinAttribute,
|
||||
};
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, DocAttribute, DocInline, InlineAttr, MirDialect, MirPhase, ReprAttr,
|
||||
SanitizerSet,
|
||||
AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase,
|
||||
ReprAttr, SanitizerSet,
|
||||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
|
|
@ -212,8 +212,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_macro_export(hir_id, *span, target)
|
||||
},
|
||||
Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target),
|
||||
Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
|
||||
self.check_eii_impl(impls, target)
|
||||
},
|
||||
Attribute::Parsed(
|
||||
AttributeKind::BodyStability { .. }
|
||||
AttributeKind::EiiExternTarget { .. }
|
||||
| AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
| AttributeKind::MacroTransparency(_)
|
||||
| AttributeKind::Pointee(..)
|
||||
|
|
@ -459,6 +463,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
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 {
|
||||
Target::Fn => {}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::EiiImplNotFunction { span: *span });
|
||||
}
|
||||
}
|
||||
|
||||
if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe)
|
||||
&& !impl_marked_unsafe
|
||||
{
|
||||
self.dcx().emit_err(errors::EiiImplRequiresUnsafe {
|
||||
span: *span,
|
||||
name: self.tcx.item_name(*eii_macro),
|
||||
suggestion: errors::EiiImplRequiresUnsafeSuggestion {
|
||||
left: inner_span.shrink_to_lo(),
|
||||
right: inner_span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no
|
||||
/// arguments.
|
||||
fn check_do_not_recommend(
|
||||
|
|
@ -684,6 +712,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
sig_span: sig.span,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpls(impls) => impls) {
|
||||
let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
|
||||
for i in impls {
|
||||
self.dcx().emit_err(errors::EiiWithTrackCaller {
|
||||
attr_span,
|
||||
name: self.tcx.item_name(i.eii_macro),
|
||||
sig_span: sig.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1305,3 +1305,42 @@ pub(crate) struct CustomMirIncompatibleDialectAndPhase {
|
|||
#[label]
|
||||
pub phase_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_eii_impl_not_function)]
|
||||
pub(crate) struct EiiImplNotFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_eii_impl_requires_unsafe)]
|
||||
pub(crate) struct EiiImplRequiresUnsafe {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: EiiImplRequiresUnsafeSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
passes_eii_impl_requires_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct EiiImplRequiresUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_eii_fn_with_track_caller)]
|
||||
pub(crate) struct EiiWithTrackCaller {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
pub name: Symbol,
|
||||
#[label]
|
||||
pub sig_span: Span,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue