Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6ce845c
Use the .drectve section for exporting symbols from dlls on Windows
bjorn3 Jun 16, 2025
729ca3f
Fix MSVC drectve exports for decorated symbols
AsakuraMizu Jun 23, 2026
c84bcbe
Use rust-lld for dll-weak-definition test
AsakuraMizu Jun 29, 2026
800fdb7
Actual fix inside `fn normalize_output`
heinwol Jun 9, 2026
15ceff0
additional: remove unnecessary `//@ normalize-stderr`
heinwol Jun 9, 2026
5b76fe0
Remove ignore directives
heinwol Jun 9, 2026
d06599e
bless stderr
heinwol Jun 9, 2026
9803c28
Rename several `//~ ERROR <...> ALLOC0` directives
heinwol Jun 9, 2026
2f749bd
Preserve MSVC import libs for empty cdylibs
AsakuraMizu Jun 30, 2026
d3e3e67
give a better error when `getrandom` fails
jyn514 Jun 25, 2026
3886e7f
Mark linux-getrandom-fallback test as needs-unwind
fs-rachel Jun 25, 2026
03d7851
add EarlyBinder<TraitRef>::def_id helper and remove direct calls to i…
Shourya742 Jun 30, 2026
cd642bb
Remove unnecessary `Clone` derives on resolver types
nnethercote Jun 30, 2026
c6f92dc
Add missing `needs_drop` check to `DroplessArena`.
nnethercote Jul 1, 2026
296ba6a
Rewrite dll-weak-definition test to run-make
AsakuraMizu Jun 30, 2026
4f436ab
Document `strip_circumfix` behavior on overlapping prefix and suffix.
theemathas Jul 1, 2026
7026b5b
fix regexes in problematic files manually
heinwol Jun 29, 2026
5eb0a5a
bless for 32bit
heinwol Jun 29, 2026
8a64598
additional failures normalization
heinwol Jul 1, 2026
c7a0991
bless from previous
heinwol Jul 1, 2026
92c10f9
Support simplest output `Self` mapping in delegation
aerooneqq Jul 1, 2026
35c2fcf
Rollup merge of #158294 - AsakuraMizu:windows-drectve-export, r=oli-obk
JonathanBrouwer Jul 1, 2026
9b11acc
Rollup merge of #156716 - heinwol:fix-ui-tests-alloc-id-parallel-fron…
JonathanBrouwer Jul 1, 2026
aad6334
Rollup merge of #158397 - aerooneqq:delegation-self-type-mapping, r=p…
JonathanBrouwer Jul 1, 2026
1f10847
Rollup merge of #158613 - fs-rachel:fix-getrandom-fallback-test, r=jo…
JonathanBrouwer Jul 1, 2026
67c06c6
Rollup merge of #158620 - Shourya742:2026-06-30-add-early-binder-def-…
JonathanBrouwer Jul 1, 2026
ca693dc
Rollup merge of #158633 - nnethercote:resolver-Clones, r=petrochenkov
JonathanBrouwer Jul 1, 2026
1c4af67
Rollup merge of #158634 - nnethercote:add-missing-needs_drop, r=Nadri…
JonathanBrouwer Jul 1, 2026
ddf0d0f
Rollup merge of #158647 - theemathas:circumfix-overlap, r=clarfonthey
JonathanBrouwer Jul 1, 2026
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
6 changes: 4 additions & 2 deletions compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,12 @@ impl DroplessArena {

#[inline]
pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
assert!(!mem::needs_drop::<T>());
assert!(size_of::<T>() != 0);

// Warning: this function is reentrant: `iter` could hold a reference to `&self` and
// allocate additional elements while we're iterating.
let iter = iter.into_iter();
assert!(size_of::<T>() != 0);
assert!(!mem::needs_drop::<T>());

let size_hint = iter.size_hint();

Expand Down Expand Up @@ -577,6 +578,7 @@ impl DroplessArena {
) -> Result<&mut [T], E> {
// Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we
// cannot know the minimum length of the iterator in this case.
assert!(!mem::needs_drop::<T>());
assert!(size_of::<T>() != 0);

// Takes care of reentrancy.
Expand Down
68 changes: 65 additions & 3 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, PerOwnerResolverData};
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::kw;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};

use crate::delegation::generics::{
GenericsGenerationResult, GenericsGenerationResults, GenericsPosition,
Expand Down Expand Up @@ -664,11 +664,34 @@ impl<'hir> LoweringContext<'_, 'hir> {

let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
let args = self.arena.alloc_from_iter(args);
let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span));
let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span);

let expr = if let Some((parent, of_trait)) = self.should_wrap_return_value(delegation) {
let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait };
let ident = Ident::new(kw::SelfUpper, span);
let path = self.create_resolved_path(res, ident, span);

// FIXME(fn_delegation): add default `..` for all other fields.
let initializer = hir::ExprKind::Struct(
self.arena.alloc(path),
self.arena.alloc_slice(&[hir::ExprField {
hir_id: self.next_id(),
is_shorthand: false,
ident: Ident::new(sym::integer(0), span),
expr: self.arena.alloc(call),
span,
}]),
hir::StructTailExpr::None,
);

self.arena.alloc(self.mk_expr(initializer, span))
} else {
self.arena.alloc(call)
};

let block = self.arena.alloc(hir::Block {
stmts,
expr: Some(call),
expr: Some(expr),
hir_id: self.next_id(),
rules: hir::BlockCheckMode::DefaultBlock,
span,
Expand All @@ -678,6 +701,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
(self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id)
}

fn should_wrap_return_value(&self, delegation: &Delegation) -> Option<(LocalDefId, bool)> {
// Heuristic: don't do wrapping if there is no target expression.
if delegation.body.is_none() {
return None;
}

let tcx = self.tcx;
let parent = tcx.local_parent(self.owner.def_id);
let parent_kind = tcx.def_kind(parent);

// Apply wrapping for delegations inside
// 1) Trait impls, as the return type of both signature function
// and generated delegation has `Self` generic param returned
// (checked below).
// FIXME(fn_delegation): think of enabling wrapping in more scenarios:
// trait-(impl)-to-free
// trait-(impl)-to-inherent
// inherent-to-free
// 2) Inherent methods when delegating to trait, as we change the type of
// `Self` to type of struct or enum we delegate from.
if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) {
return None;
}

let is_trait_impl = parent_kind == DefKind::Impl { of_trait: true };

// Check that delegation path resolves to a trait AssocFn, not to a free method.
Some((parent, is_trait_impl)).filter(|_| {
self.get_resolution_id(delegation.id).is_some_and(|id| {
tcx.def_kind(id) == DefKind::AssocFn
// Check that the return type of the callee is `Self` param.
// After previous check we are sure that `sig_id` and `delegation.id`
// point to the same function.
&& tcx.def_kind(tcx.parent(id)) == DefKind::Trait
&& tcx.fn_sig(id).skip_binder().output().skip_binder().is_param(0)
})
})
}

fn process_segment(
&mut self,
span: Span,
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,19 +588,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
p.def_id.to_def_id(),
);

self.create_resolved_path(res, p.name.ident(), p.span)
}

pub(super) fn create_resolved_path(
&mut self,
res: Res,
ident: Ident,
span: Span,
) -> hir::QPath<'hir> {
hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
segments: self.arena.alloc_slice(&[hir::PathSegment {
args: None,
hir_id: self.next_id(),
ident: p.name.ident(),
ident,
infer_args: false,
res,
delegation_child_segment: false,
}]),
res,
span: p.span,
span,
}),
)
}
Expand Down
67 changes: 59 additions & 8 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ use super::rmeta_link::RmetaLinkCache;
use super::rpath::{self, RPathConfig};
use super::{apple, rmeta_link, versioned_llvm_target};
use crate::base::needs_allocator_shim_for_linking;
use crate::{CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors};
use crate::{
CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, SymbolExport,
errors,
};

pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
if let Err(e) = fs::remove_file(path) {
Expand Down Expand Up @@ -593,7 +596,7 @@ fn link_staticlib(
crate_info
.exported_symbols
.get(&CrateType::StaticLib)
.map(|symbols| symbols.iter().map(|(s, _)| s.clone()).collect())
.map(|symbols| symbols.iter().map(|symbol| symbol.name.clone()).collect())
}
} else {
None
Expand Down Expand Up @@ -2196,9 +2199,15 @@ fn add_linked_symbol_object(
cmd: &mut dyn Linker,
sess: &Session,
tmpdir: &Path,
symbols: &[(String, SymbolExportKind)],
crate_type: CrateType,
linked_symbols: &[(String, SymbolExportKind)],
exported_symbols: &[SymbolExport],
) {
if symbols.is_empty() {
let should_export_symbols = sess.target.is_like_msvc
&& !exported_symbols.is_empty()
&& (crate_type != CrateType::Executable
|| sess.opts.unstable_opts.export_executable_symbols);
if linked_symbols.is_empty() && !should_export_symbols {
return;
}

Expand Down Expand Up @@ -2235,7 +2244,7 @@ fn add_linked_symbol_object(
None
};

for (sym, kind) in symbols.iter() {
for (sym, kind) in linked_symbols.iter() {
let symbol = file.add_symbol(object::write::Symbol {
name: sym.clone().into(),
value: 0,
Expand Down Expand Up @@ -2293,6 +2302,37 @@ fn add_linked_symbol_object(
}
}

if should_export_symbols {
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
// export symbols from a dynamic library. When building a dynamic library,
// however, we're going to want some symbols exported, so this adds a
// `.drectve` section which lists all the symbols using /EXPORT arguments.
//
// The linker will read these arguments from the `.drectve` section and
// export all the symbols from the dynamic library. Note that this is not
// as simple as just exporting all the symbols in the current crate (as
// specified by `codegen.reachable`) but rather we also need to possibly
// export the symbols of upstream crates. Upstream rlibs may be linked
// statically to this dynamic library, in which case they may continue to
// transitively be used and hence need their symbols exported.
fn msvc_drectve_export(symbol: &SymbolExport) -> String {
let data = if symbol.kind == SymbolExportKind::Data { ",DATA" } else { "" };

if let Some(link_name) = symbol.link_name.as_deref() {
// The first name is the decorated symbol used by the import library, while
// EXPORTAS gives the public name written to the DLL export table.
format!(" /EXPORT:\"{link_name}\"{data},EXPORTAS,\"{}\"", symbol.name)
} else {
format!(" /EXPORT:\"{}\"{data}", symbol.name)
}
}

let drectve = exported_symbols.iter().map(msvc_drectve_export).collect::<String>();

let section = file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker);
file.append_section_data(section, drectve.as_bytes(), 1);
}

let path = tmpdir.join("symbols.o");
let result = std::fs::write(&path, file.write().unwrap());
if let Err(error) = result {
Expand Down Expand Up @@ -2486,7 +2526,7 @@ fn undecorate_c_symbol<'a>(
fn add_c_staticlib_symbols(
sess: &Session,
lib: &NativeLib,
out: &mut Vec<(String, SymbolExportKind)>,
out: &mut Vec<SymbolExport>,
) -> io::Result<()> {
let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);

Expand Down Expand Up @@ -2549,7 +2589,11 @@ fn add_c_staticlib_symbols(
let Some(undecorated) = undecorate_c_symbol(name, sess, export_kind) else {
continue;
};
out.push((undecorated.to_string(), export_kind));
out.push(SymbolExport::with_link_name(
undecorated.to_string(),
export_kind,
name.to_string(),
));
}
}

Expand Down Expand Up @@ -2629,7 +2673,14 @@ fn linker_with_args(
// Pre-link CRT objects.
add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained_crt_objects);

add_linked_symbol_object(cmd, sess, tmpdir, &crate_info.linked_symbols[&crate_type]);
add_linked_symbol_object(
cmd,
sess,
tmpdir,
crate_type,
&crate_info.linked_symbols[&crate_type],
&export_symbols,
);

// Sanitizer libraries.
add_sanitizer_libraries(sess, flavor, crate_type, cmd);
Expand Down
Loading
Loading