Skip to content
Merged
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
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3924,7 +3924,7 @@ pub struct EiiImpl {
///
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
pub known_eii_macro_resolution: Option<EiiDecl>,
pub known_eii_macro_resolution: Option<Path>,
pub impl_safety: Safety,
pub span: Span,
pub inner_span: Span,
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
}: &EiiImpl,
) -> hir::attrs::EiiImpl {
let resolution = if let Some(target) = known_eii_macro_resolution
&& let Some(decl) = self.lower_eii_decl(
*node_id,
// the expect is ok here since we always generate this path in the eii macro.
eii_macro_path.segments.last().expect("at least one segment").ident,
target,
) {
EiiImplResolution::Known(decl)
&& let Some(foreign_item_did) = self.lower_path_simple_eii(*node_id, target)
{
EiiImplResolution::Known(foreign_item_did)
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
EiiImplResolution::Macro(macro_did)
} else {
Expand Down
15 changes: 6 additions & 9 deletions compiler/rustc_builtin_macros/src/eii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,12 @@ fn generate_default_impl(
},
span: eii_attr_span,
is_default: true,
known_eii_macro_resolution: Some(ast::EiiDecl {
foreign_item: ecx.path(
foreign_item_name.span,
// prefix self to explicitly escape the const block generated below
// NOTE: this is why EIIs can't be used on statements
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
),
impl_unsafe,
}),
known_eii_macro_resolution: Some(ecx.path(
foreign_item_name.span,
// prefix self to explicitly escape the const block generated below
// NOTE: this is why EIIs can't be used on statements
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
)),
};

let mut item_kind = item_kind.clone();
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, find_attr};
use rustc_macros::Diagnostic;
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, InstrumentFnAttr, PatchableFunctionEntry, SanitizerFnAttrs,
};
Expand Down Expand Up @@ -238,7 +239,7 @@ fn process_builtin_attrs(
};
extern_item
}
EiiImplResolution::Known(decl) => decl.foreign_item,
EiiImplResolution::Known(def_id) => def_id,
EiiImplResolution::Error(_eg) => continue,
};

Expand All @@ -253,7 +254,10 @@ fn process_builtin_attrs(
// iterate over all implementations *in the current crate*
// (this is ok since we generate codegen fn attrs in the local crate)
// if any of them is *not default* then don't emit the alias.
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
&& {
let (_, impls) = tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).unwrap_or_else(|| bug!("EII impl should have an entry"));
impls.iter().any(|(_, imp)| !imp.is_default)
}
{
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub enum EiiImplResolution {
/// what foreign item its associated with.
Macro(DefId),
/// Sometimes though, we already know statically and can skip some name resolution.
/// Stored together with the eii's name for diagnostics.
Known(EiiDecl),
/// DefId of the extern item that the EII implementation implements.
Known(DefId),
/// For when resolution failed, but we want to continue compilation
Error(ErrorGuaranteed),
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) {
continue;
}
}
EiiImplResolution::Known(decl) => (decl.foreign_item, decl.name.name),
EiiImplResolution::Known(def_id) => (*def_id, tcx.item_name(*def_id)),
EiiImplResolution::Error(_eg) => continue,
};

Expand All @@ -1259,7 +1259,7 @@ fn check_eiis_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, ty: Ty<'tcx>)
continue;
}
}
EiiImplResolution::Known(decl) => (decl.foreign_item, decl.name.name),
EiiImplResolution::Known(def_id) => (*def_id, tcx.item_name(*def_id)),
EiiImplResolution::Error(_eg) => continue,
};

Expand Down
28 changes: 23 additions & 5 deletions compiler/rustc_metadata/src/eii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::attrs::{EiiDecl, EiiImpl, EiiImplResolution};
use rustc_hir::def_id::DefId;
use rustc_hir::find_attr;
use rustc_middle::bug;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::TyCtxt;

Expand All @@ -23,10 +24,19 @@ pub(crate) type EiiMap = FxIndexMap<
pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap {
let mut eiis = EiiMap::default();

// Needed because Known only stores a DefId (not the full EiiDecl),
// and we can't call the externally_implementable_items query (cycle).
let decls_by_foreign_item: FxIndexMap<DefId, EiiDecl> = tcx
.hir_crate_items(())
.eiis()
.filter_map(|id| find_attr!(tcx, id, EiiDeclaration(d) => *d))
.map(|decl| (decl.foreign_item, decl))
.collect();

// iterate over all items in the current crate
for id in tcx.hir_crate_items(()).eiis() {
for i in find_attr!(tcx, id, EiiImpls(e) => e).into_flat_iter() {
let decl = match i.resolution {
let (foreign_item, decl) = match i.resolution {
EiiImplResolution::Macro(macro_defid) => {
// find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal)
let Some(decl) = find_attr!(tcx, macro_defid, EiiDeclaration(d) => *d) else {
Expand All @@ -35,14 +45,22 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap
.span_delayed_bug(i.span, "resolved to something that's not an EII");
continue;
};
decl
(decl.foreign_item, decl)
}
// Recover the EiiDecl from the local lookup map.
EiiImplResolution::Known(foreign_item_did) => {
let decl = decls_by_foreign_item.get(&foreign_item_did).unwrap_or_else(|| {
bug!(
"EII impl has Known resolution but can't find EiiDeclaration for {:?}",
foreign_item_did
)
});
(foreign_item_did, *decl)
}
EiiImplResolution::Known(decl) => decl,
EiiImplResolution::Error(_eg) => continue,
};

// FIXME(eii) remove extern target from encoded decl
eiis.entry(decl.foreign_item)
eiis.entry(foreign_item)
.or_insert_with(|| (decl, Default::default()))
.1
.insert(id.into(), *i);
Expand Down
29 changes: 23 additions & 6 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,13 +486,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

if let EiiImplResolution::Macro(eii_macro) = resolution
&& find_attr!(self.tcx, *eii_macro, EiiDeclaration(EiiDecl { impl_unsafe, .. }) if *impl_unsafe)
&& !impl_marked_unsafe
{
let needs_unsafe = match resolution {
EiiImplResolution::Macro(eii_macro) => {
find_attr!(self.tcx, *eii_macro, EiiDeclaration(EiiDecl { impl_unsafe, .. }) if *impl_unsafe)
}
EiiImplResolution::Known(foreign_item_did) => {
let foreign_item_did = *foreign_item_did;
self.tcx
.externally_implementable_items(foreign_item_did.krate)
.get(&foreign_item_did)
.map(|(decl, _)| decl.impl_unsafe)
.unwrap_or(false)
}
EiiImplResolution::Error(_) => false,
};

if needs_unsafe && !impl_marked_unsafe {
let name = match resolution {
EiiImplResolution::Macro(eii_macro) => self.tcx.item_name(*eii_macro),
EiiImplResolution::Known(def_id) => self.tcx.item_name(*def_id),
EiiImplResolution::Error(_) => unreachable!(),
};
self.dcx().emit_err(diagnostics::EiiImplRequiresUnsafe {
span: *span,
name: self.tcx.item_name(*eii_macro),
name,
suggestion: diagnostics::EiiImplRequiresUnsafeSuggestion {
left: inner_span.shrink_to_lo(),
right: inner_span.shrink_to_hi(),
Expand Down Expand Up @@ -755,7 +772,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
for i in impls {
let name = match i.resolution {
EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id),
EiiImplResolution::Known(decl) => decl.name.name,
EiiImplResolution::Known(def_id) => self.tcx.item_name(def_id),
EiiImplResolution::Error(_eg) => continue,
};
self.dcx().emit_err(diagnostics::EiiWithTrackCaller {
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5609,12 +5609,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// See docs on the `known_eii_macro_resolution` field:
// if we already know the resolution statically, don't bother resolving it.
if let Some(target) = known_eii_macro_resolution {
self.smart_resolve_path(
*node_id,
&None,
&target.foreign_item,
PathSource::ExternItemImpl,
);
self.smart_resolve_path(*node_id, &None, target, PathSource::ExternItemImpl);
} else {
self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro);
}
Expand Down
Loading