Skip to content
13 changes: 13 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3867,6 +3867,19 @@ pub struct Fn {
pub eii_impls: ThinVec<EiiImpl>,
}

impl Fn {
pub fn is_pin_drop_sugar(&self) -> bool {
self.ident.name == sym::drop
&& self
.sig
.decl
.inputs
.first()
.and_then(|param| param.to_self())
.is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut)))
}
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct EiiImpl {
pub node_id: NodeId,
Expand Down
73 changes: 56 additions & 17 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,52 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}

fn resolve_pin_drop_sugar_impl_item(
&self,
i: &AssocItem,
ident: Ident,
span: Span,
) -> (Ident, Result<DefId, ErrorGuaranteed>) {
let trait_item_def_id = self
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(span, "could not resolve trait item being implemented")
});

let is_pin_drop_sugar = match &i.kind {
AssocItemKind::Fn(fn_kind) => fn_kind.is_pin_drop_sugar(),
_ => false,
};
let def_id = match trait_item_def_id {
Ok(def_id) => def_id,
Err(guar) => return (ident, Err(guar)),
};
if !is_pin_drop_sugar {
return (ident, Ok(def_id));
}

let is_drop_pin_drop = self
.tcx
.lang_items()
.drop_trait()
.is_some_and(|drop_trait| self.tcx.parent(def_id) == drop_trait);
if is_drop_pin_drop {
// Associated item collection still derives the impl item's name from HIR.
return (Ident::new(sym::pin_drop, ident.span), Ok(def_id));
}

let guar = self
.dcx()
.struct_span_err(
i.span,
"method `drop` with `&pin mut self` is only supported for the `Drop` trait",
)
.with_span_label(i.span, "not a `Drop::pin_drop` implementation")
.emit();
(ident, Err(guar))
}

fn lower_impl_item(
&mut self,
i: &AssocItem,
Expand Down Expand Up @@ -1309,26 +1355,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
};

let span = self.lower_span(i.span);
let (effective_ident, impl_kind) = if is_in_trait_impl {
let (effective_ident, trait_item_def_id) =
self.resolve_pin_drop_sugar_impl_item(i, ident, span);
(effective_ident, ImplItemImplKind::Trait { defaultness, trait_item_def_id })
} else {
(ident, ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) })
};

let item = hir::ImplItem {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
ident: self.lower_ident(effective_ident),
generics,
impl_kind: if is_in_trait_impl {
ImplItemImplKind::Trait {
defaultness,
trait_item_def_id: self
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(
span,
"could not resolve trait item being implemented",
)
}),
}
} else {
ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }
},
impl_kind,
kind,
span,
has_delayed_lints: !self.delayed_lints.is_empty(),
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_middle::ty::{
use rustc_span::{ErrorGuaranteed, Span, kw};

use crate::collect::ItemCtxt;
use crate::errors::DelegationSelfTypeNotSpecified;
use crate::hir_ty_lowering::HirTyLowerer;

type RemapTable = FxHashMap<u32, u32>;
Expand Down Expand Up @@ -284,6 +285,12 @@ fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) ->
ctx.lower_ty(tcx.hir_node(id).expect_ty())
})
.unwrap_or_else(|| {
// It is possible to attempt to get self type when it is used in signature
// (i.e., `fn default() -> Self`), so emit error here in addition to possible
// `mismatched types` error (see #156388).
let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) };
tcx.dcx().emit_err(err);

Ty::new_error_with_message(
tcx,
tcx.def_span(delegation_id),
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,14 @@ pub(crate) struct UnsupportedDelegation<'a> {
pub callee_span: Span,
}

#[derive(Diagnostic)]
#[diag("delegation self type is not specified")]
#[help("consider explicitly specifying self type: `reuse </* Type */ as Trait>::function`")]
pub(crate) struct DelegationSelfTypeNotSpecified {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("method should be `async` or return a future, but it is synchronous")]
pub(crate) struct MethodShouldReturnFuture {
Expand Down
17 changes: 14 additions & 3 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3612,6 +3612,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
this.check_trait_item(
item.id,
*ident,
*ident,
&item.kind,
ValueNS,
item.span,
Expand Down Expand Up @@ -3656,7 +3657,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
self.resolve_define_opaques(define_opaque);
}
AssocItemKind::Fn(Fn { ident, generics, define_opaque, .. }) => {
AssocItemKind::Fn(fn_kind @ Fn { ident, generics, define_opaque, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
self.with_generic_param_rib(
Expand All @@ -3666,10 +3667,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
LifetimeBinderKind::Function,
generics.span,
|this| {
let effective_ident = if is_in_trait_impl && fn_kind.is_pin_drop_sugar() {
Ident::new(sym::pin_drop, ident.span)
} else {
*ident
};
// If this is a trait impl, ensure the method
// exists in trait
this.check_trait_item(
item.id,
effective_ident,
*ident,
&item.kind,
ValueNS,
Expand Down Expand Up @@ -3701,6 +3708,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
this.check_trait_item(
item.id,
*ident,
*ident,
&item.kind,
TypeNS,
item.span,
Expand All @@ -3726,6 +3734,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
this.check_trait_item(
item.id,
delegation.ident,
delegation.ident,
&item.kind,
ValueNS,
item.span,
Expand All @@ -3750,6 +3759,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
&mut self,
id: NodeId,
mut ident: Ident,
mut reported_ident: Ident,
kind: &AssocItemKind,
ns: Namespace,
span: Span,
Expand All @@ -3763,6 +3773,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
return;
};
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
reported_ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
let key = BindingKey::new(IdentKey::new(ident), ns);
let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl());
debug!(?decl);
Expand Down Expand Up @@ -3798,10 +3809,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

let Some(decl) = decl else {
// We could not find the method: report an error.
let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
let candidate = self.find_similarly_named_assoc_item(reported_ident.name, kind);
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
let path_names = path_names_to_string(path);
self.report_error(span, err(ident, path_names, candidate));
self.report_error(span, err(reported_ident, path_names, candidate));
feed_visibility(self, module.def_id());
return;
};
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_target/src/spec/base/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ pub(crate) fn options() -> TargetOptions {
// with unwinding.
llvm_args: cvs!["-wasm-use-legacy-eh=false"],

// WASI's `sys::args::init` function ignores its arguments; instead,
// `args::args()` makes the WASI API calls itself.
//
// Other Wasm targets make no use of `std::env` entirely.
// Emscripten enables it explicitly.
main_needs_argc_argv: false,

..Default::default()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) fn target() -> Target {
crt_static_respected: true,
crt_static_default: true,
crt_static_allows_dylibs: true,
main_needs_argc_argv: true,
panic_strategy: PanicStrategy::Unwind,
no_default_libraries: false,
families: cvs!["unix", "wasm"],
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ pub(crate) fn target() -> Target {
// without a main function.
options.crt_static_allows_dylibs = true;

// WASI's `sys::args::init` function ignores its arguments; instead,
// `args::args()` makes the WASI API calls itself.
options.main_needs_argc_argv = false;

// And, WASI mangles the name of "main" to distinguish between different
// signatures.
options.entry_name = "__main_void".into();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ pub(crate) fn target() -> Target {
// without a main function.
options.crt_static_allows_dylibs = true;

// WASI's `sys::args::init` function ignores its arguments; instead,
// `args::args()` makes the WASI API calls itself.
options.main_needs_argc_argv = false;

// And, WASI mangles the name of "main" to distinguish between different
// signatures.
options.entry_name = "__main_void".into();
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ pub(crate) fn target() -> Target {
// without a main function.
options.crt_static_allows_dylibs = true;

// WASI's `sys::args::init` function ignores its arguments; instead,
// `args::args()` makes the WASI API calls itself.
options.main_needs_argc_argv = false;

// And, WASI mangles the name of "main" to distinguish between different
// signatures.
options.entry_name = "__main_void".into();
Expand Down
49 changes: 32 additions & 17 deletions tests/run-make/remap-path-prefix-std/rmake.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This test makes sure that we do not leak paths to the checkout
// (i.e. /checkout in CI) in the distributed `libstd` debuginfo.
// (ie. /checkout in CI) in the distributed standard library debuginfo.
// It checks all rlibs found in the target libdir, not just libstd.
//
// This test only runs on Linux and dist builder (or with `rust.remap-debuginfo = true`
// set in your `bootstrap.toml`).
Expand All @@ -24,30 +25,44 @@ fn main() {
path
};

// Find all the `libstd-.*.rlib` files under the libdir
let libstd_rlibs = shallow_find_files(&target_libdir, |p| {
// Find all rlib files under the libdir (the full standard library set)
let all_rlibs = shallow_find_files(&target_libdir, |p| {
if let Some(filename) = p.file_name()
&& let filename = filename.to_string_lossy()
&& let Some(ext) = p.extension()
&& filename.starts_with("lib")
&& ext == "rlib"
{
filename.starts_with("libstd-") && filename.ends_with(".rlib")
true
} else {
false
}
});

// Assert that there is only one rlib for the `libstd`
let [libstd_rlib] = &libstd_rlibs[..] else {
unreachable!("multiple libstd rlib: {libstd_rlibs:?} in {target_libdir:?}");
};
// There must be at least one rlib (libstd itself, plus many others)
assert!(!all_rlibs.is_empty(), "no rlibs found in target libdir {target_libdir:?}");

for rlib in &all_rlibs {
// Use a stable symlink name based on the crate part (before the '-<hash>' suffix).
// e.g. "libstd-92abaa9b58c011c1.rlib" → "libstd.rlib"
let filename = rlib.file_name().unwrap().to_string_lossy();
let link_name = match filename.split_once('-') {
Some((prefix, _)) => format!("{prefix}.rlib"),
None => filename.to_string(),
};

// Symlink the libstd rlib here to avoid absolute paths from llvm-dwarfdump own output
// and not from the debuginfo it-self
rfs::symlink_file(libstd_rlib, "libstd.rlib");
// Symlink the original rlib to avoid absolute paths from dwarfdump itself
rfs::symlink_file(rlib, &link_name);

// Check that there is only `/rustc/` paths and no `/checkout`, `/home`, or whatever
llvm_dwarfdump()
.input("libstd.rlib")
.run()
.assert_stdout_contains("/rustc/")
.assert_stdout_not_contains(source_root().to_string_lossy());
// Check that no distributed rlib leaks the checkout/source root path.
let completed = llvm_dwarfdump()
.input(&link_name)
.run()
.assert_stdout_not_contains(source_root().to_string_lossy());

// Check that we have `/rustc` in the output if the rlib has any debug info.
if completed.stdout_utf8().contains("DW_TAG_compile_unit") {
completed.assert_stdout_contains("/rustc");
}
}
}
6 changes: 6 additions & 0 deletions tests/ui/delegation/generics/free-to-trait-static-reuse.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//@ compile-flags: -Z deduplicate-diagnostics=yes

#![feature(fn_delegation)]

trait Bound<T> {}
Expand All @@ -19,12 +21,16 @@ reuse <usize as Trait>::static_method::<'static, Vec<i32>, false> as bar2;

reuse Trait::static_method as error { self - 123 }
//~^ ERROR: type annotations needed
//~| ERROR: delegation self type is not specified
reuse Trait::<'static, i32, 123>::static_method as error2;
//~^ ERROR: type annotations needed
//~| ERROR: delegation self type is not specified
reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3;
//~^ ERROR: type annotations needed
//~| ERROR: delegation self type is not specified
reuse Trait::static_method::<'static, Vec<i32>, false> as error4 { self + 4 }
//~^ ERROR: type annotations needed
//~| ERROR: delegation self type is not specified

reuse <String as Trait>::static_method as error5;
//~^ ERROR: the trait bound `String: Trait<'a, T, X>` is not satisfied
Expand Down
Loading
Loading