Skip to content

Commit 4586feb

Browse files
Auto merge of #150810 - matthiaskrgr:rollup-fXh6V3q, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #149976 (Add waker_fn and local_waker_fn to std::task) - #150074 (Update provider API docs) - #150094 (`c_variadic`: provide our own `va_arg` implementation for more targets) - #150164 (rustc: Fix `-Zexport-executable-symbols` on wasm) - #150569 (Ensure that static initializers are acyclic for NVPTX) - #150694 (./x check miri: enable check_only feature) - #150717 (Thread `--jobs` from `bootstrap` -> `compiletest` -> `run-make-support`) - #150736 (Add AtomicPtr::null) - #150787 (Add myself as co-maintainer for s390x-unknown-linux-musl) - #150789 (Fix copy-n-paste error in `vtable_for` docs) r? @ghost
2 parents 32fe406 + 5a5740f commit 4586feb

File tree

32 files changed

+537
-37
lines changed

32 files changed

+537
-37
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4421,6 +4421,7 @@ dependencies = [
44214421
"rustc_errors",
44224422
"rustc_fluent_macro",
44234423
"rustc_hir",
4424+
"rustc_index",
44244425
"rustc_macros",
44254426
"rustc_middle",
44264427
"rustc_session",

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout};
1+
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size};
22
use rustc_codegen_ssa::MemFlags;
33
use rustc_codegen_ssa::common::IntPredicate;
44
use rustc_codegen_ssa::mir::operand::OperandRef;
55
use rustc_codegen_ssa::traits::{
66
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods,
77
};
8+
use rustc_middle::bug;
89
use rustc_middle::ty::Ty;
9-
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
10+
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
1011
use rustc_target::spec::{Abi, Arch, Env};
1112

1213
use crate::builder::Builder;
@@ -82,6 +83,7 @@ enum PassMode {
8283
enum SlotSize {
8384
Bytes8 = 8,
8485
Bytes4 = 4,
86+
Bytes1 = 1,
8587
}
8688

8789
enum AllowHigherAlign {
@@ -728,7 +730,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
728730
fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
729731
bx: &mut Builder<'_, 'll, 'tcx>,
730732
reg_addr: &'ll Value,
731-
layout: TyAndLayout<'tcx, Ty<'tcx>>,
733+
layout: TyAndLayout<'tcx>,
732734
src_align: Align,
733735
) -> &'ll Value {
734736
if layout.layout.align.abi > src_align {
@@ -751,7 +753,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
751753
fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
752754
bx: &mut Builder<'_, 'll, 'tcx>,
753755
va_list_addr: &'ll Value,
754-
layout: TyAndLayout<'tcx, Ty<'tcx>>,
756+
layout: TyAndLayout<'tcx>,
755757
) -> &'ll Value {
756758
let dl = bx.cx.data_layout();
757759
let ptr_align_abi = dl.data_layout().pointer_align().abi;
@@ -1003,15 +1005,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
10031005
return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi);
10041006
}
10051007

1008+
/// Determine the va_arg implementation to use. The LLVM va_arg instruction
1009+
/// is lacking in some instances, so we should only use it as a fallback.
10061010
pub(super) fn emit_va_arg<'ll, 'tcx>(
10071011
bx: &mut Builder<'_, 'll, 'tcx>,
10081012
addr: OperandRef<'tcx, &'ll Value>,
10091013
target_ty: Ty<'tcx>,
10101014
) -> &'ll Value {
1011-
// Determine the va_arg implementation to use. The LLVM va_arg instruction
1012-
// is lacking in some instances, so we should only use it as a fallback.
1013-
let target = &bx.cx.tcx.sess.target;
1015+
let layout = bx.cx.layout_of(target_ty);
1016+
let target_ty_size = layout.layout.size().bytes();
10141017

1018+
let target = &bx.cx.tcx.sess.target;
10151019
match target.arch {
10161020
Arch::X86 => emit_ptr_va_arg(
10171021
bx,
@@ -1069,23 +1073,79 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10691073
AllowHigherAlign::Yes,
10701074
ForceRightAdjust::No,
10711075
),
1076+
Arch::LoongArch32 => emit_ptr_va_arg(
1077+
bx,
1078+
addr,
1079+
target_ty,
1080+
if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct },
1081+
SlotSize::Bytes4,
1082+
AllowHigherAlign::Yes,
1083+
ForceRightAdjust::No,
1084+
),
1085+
Arch::LoongArch64 => emit_ptr_va_arg(
1086+
bx,
1087+
addr,
1088+
target_ty,
1089+
if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
1090+
SlotSize::Bytes8,
1091+
AllowHigherAlign::Yes,
1092+
ForceRightAdjust::No,
1093+
),
1094+
Arch::AmdGpu => emit_ptr_va_arg(
1095+
bx,
1096+
addr,
1097+
target_ty,
1098+
PassMode::Direct,
1099+
SlotSize::Bytes4,
1100+
AllowHigherAlign::No,
1101+
ForceRightAdjust::No,
1102+
),
1103+
Arch::Nvptx64 => emit_ptr_va_arg(
1104+
bx,
1105+
addr,
1106+
target_ty,
1107+
PassMode::Direct,
1108+
SlotSize::Bytes1,
1109+
AllowHigherAlign::Yes,
1110+
ForceRightAdjust::No,
1111+
),
1112+
Arch::Wasm32 => emit_ptr_va_arg(
1113+
bx,
1114+
addr,
1115+
target_ty,
1116+
if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() {
1117+
PassMode::Indirect
1118+
} else {
1119+
PassMode::Direct
1120+
},
1121+
SlotSize::Bytes4,
1122+
AllowHigherAlign::Yes,
1123+
ForceRightAdjust::No,
1124+
),
1125+
Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"),
1126+
Arch::CSky => emit_ptr_va_arg(
1127+
bx,
1128+
addr,
1129+
target_ty,
1130+
PassMode::Direct,
1131+
SlotSize::Bytes4,
1132+
AllowHigherAlign::Yes,
1133+
ForceRightAdjust::No,
1134+
),
10721135
// Windows x86_64
1073-
Arch::X86_64 if target.is_like_windows => {
1074-
let target_ty_size = bx.cx.size_of(target_ty).bytes();
1075-
emit_ptr_va_arg(
1076-
bx,
1077-
addr,
1078-
target_ty,
1079-
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
1080-
PassMode::Indirect
1081-
} else {
1082-
PassMode::Direct
1083-
},
1084-
SlotSize::Bytes8,
1085-
AllowHigherAlign::No,
1086-
ForceRightAdjust::No,
1087-
)
1088-
}
1136+
Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg(
1137+
bx,
1138+
addr,
1139+
target_ty,
1140+
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
1141+
PassMode::Indirect
1142+
} else {
1143+
PassMode::Direct
1144+
},
1145+
SlotSize::Bytes8,
1146+
AllowHigherAlign::No,
1147+
ForceRightAdjust::No,
1148+
),
10891149
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
10901150
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
10911151
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),

compiler/rustc_codegen_ssa/src/back/linker.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,11 @@ impl<'a> Linker for GccLinker<'a> {
839839
self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
840840
}
841841
self.link_arg(path);
842+
} else if self.sess.target.is_like_wasm {
843+
self.link_arg("--no-export-dynamic");
844+
for (sym, _) in symbols {
845+
self.link_arg("--export").link_arg(sym);
846+
}
842847
} else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
843848
let res: io::Result<()> = try {
844849
let mut f = File::create_buffered(&path)?;
@@ -853,11 +858,6 @@ impl<'a> Linker for GccLinker<'a> {
853858
self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
854859
}
855860
self.link_arg("--dynamic-list").link_arg(path);
856-
} else if self.sess.target.is_like_wasm {
857-
self.link_arg("--no-export-dynamic");
858-
for (sym, _) in symbols {
859-
self.link_arg("--export").link_arg(sym);
860-
}
861861
} else {
862862
// Write an LD version script
863863
let res: io::Result<()> = try {

compiler/rustc_monomorphize/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
1010
rustc_errors = { path = "../rustc_errors" }
1111
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1212
rustc_hir = { path = "../rustc_hir" }
13+
rustc_index = { path = "../rustc_index" }
1314
rustc_macros = { path = "../rustc_macros" }
1415
rustc_middle = { path = "../rustc_middle" }
1516
rustc_session = { path = "../rustc_session" }

compiler/rustc_monomorphize/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,8 @@ monomorphize_recursion_limit =
7575
monomorphize_start_not_found = using `fn main` requires the standard library
7676
.help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]`
7777
78+
monomorphize_static_initializer_cyclic = static initializer forms a cycle involving `{$head}`
79+
.label = part of this cycle
80+
.note = cyclic static initializers are not supported for target `{$target}`
81+
7882
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ pub(crate) struct UsageMap<'tcx> {
267267
// Maps every mono item to the mono items used by it.
268268
pub used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
269269

270-
// Maps every mono item to the mono items that use it.
270+
// Maps each mono item with users to the mono items that use it.
271+
// Be careful: subsets `used_map`, so unused items are vacant.
271272
user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
272273
}
273274

compiler/rustc_monomorphize/src/errors.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,15 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
117117
/// Whether this is a problem at a call site or at a declaration.
118118
pub is_call: bool,
119119
}
120+
121+
#[derive(Diagnostic)]
122+
#[diag(monomorphize_static_initializer_cyclic)]
123+
#[note]
124+
pub(crate) struct StaticInitializerCyclic<'a> {
125+
#[primary_span]
126+
pub span: Span,
127+
#[label]
128+
pub labels: Vec<Span>,
129+
pub head: &'a str,
130+
pub target: &'a str,
131+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! Checks that need to operate on the entire mono item graph
2+
use rustc_middle::mir::mono::MonoItem;
3+
use rustc_middle::ty::TyCtxt;
4+
5+
use crate::collector::UsageMap;
6+
use crate::graph_checks::statics::check_static_initializers_are_acyclic;
7+
8+
mod statics;
9+
10+
pub(super) fn target_specific_checks<'tcx, 'a, 'b>(
11+
tcx: TyCtxt<'tcx>,
12+
mono_items: &'a [MonoItem<'tcx>],
13+
usage_map: &'b UsageMap<'tcx>,
14+
) {
15+
if tcx.sess.target.options.static_initializer_must_be_acyclic {
16+
check_static_initializers_are_acyclic(tcx, mono_items, usage_map);
17+
}
18+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use rustc_data_structures::fx::FxIndexSet;
2+
use rustc_data_structures::graph::scc::Sccs;
3+
use rustc_data_structures::graph::{DirectedGraph, Successors};
4+
use rustc_data_structures::unord::UnordMap;
5+
use rustc_hir::def_id::DefId;
6+
use rustc_index::{Idx, IndexVec, newtype_index};
7+
use rustc_middle::mir::mono::MonoItem;
8+
use rustc_middle::ty::TyCtxt;
9+
10+
use crate::collector::UsageMap;
11+
use crate::errors;
12+
13+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14+
struct StaticNodeIdx(usize);
15+
16+
impl Idx for StaticNodeIdx {
17+
fn new(idx: usize) -> Self {
18+
Self(idx)
19+
}
20+
21+
fn index(self) -> usize {
22+
self.0
23+
}
24+
}
25+
26+
impl From<usize> for StaticNodeIdx {
27+
fn from(value: usize) -> Self {
28+
StaticNodeIdx(value)
29+
}
30+
}
31+
32+
newtype_index! {
33+
#[derive(Ord, PartialOrd)]
34+
struct StaticSccIdx {}
35+
}
36+
37+
// Adjacency-list graph for statics using `StaticNodeIdx` as node type.
38+
// We cannot use `DefId` as the node type directly because each node must be
39+
// represented by an index in the range `0..num_nodes`.
40+
struct StaticRefGraph<'a, 'b, 'tcx> {
41+
// maps from `StaticNodeIdx` to `DefId` and vice versa
42+
statics: &'a FxIndexSet<DefId>,
43+
// contains for each `MonoItem` the `MonoItem`s it uses
44+
used_map: &'b UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
45+
}
46+
47+
impl<'a, 'b, 'tcx> DirectedGraph for StaticRefGraph<'a, 'b, 'tcx> {
48+
type Node = StaticNodeIdx;
49+
50+
fn num_nodes(&self) -> usize {
51+
self.statics.len()
52+
}
53+
}
54+
55+
impl<'a, 'b, 'tcx> Successors for StaticRefGraph<'a, 'b, 'tcx> {
56+
fn successors(&self, node_idx: StaticNodeIdx) -> impl Iterator<Item = StaticNodeIdx> {
57+
let def_id = self.statics[node_idx.index()];
58+
self.used_map[&MonoItem::Static(def_id)].iter().filter_map(|&mono_item| match mono_item {
59+
MonoItem::Static(def_id) => self.statics.get_index_of(&def_id).map(|idx| idx.into()),
60+
_ => None,
61+
})
62+
}
63+
}
64+
65+
pub(super) fn check_static_initializers_are_acyclic<'tcx, 'a, 'b>(
66+
tcx: TyCtxt<'tcx>,
67+
mono_items: &'a [MonoItem<'tcx>],
68+
usage_map: &'b UsageMap<'tcx>,
69+
) {
70+
// Collect statics
71+
let statics: FxIndexSet<DefId> = mono_items
72+
.iter()
73+
.filter_map(|&mono_item| match mono_item {
74+
MonoItem::Static(def_id) => Some(def_id),
75+
_ => None,
76+
})
77+
.collect();
78+
79+
// If we don't have any statics the check is not necessary
80+
if statics.is_empty() {
81+
return;
82+
}
83+
// Create a subgraph from the mono item graph, which only contains statics
84+
let graph = StaticRefGraph { statics: &statics, used_map: &usage_map.used_map };
85+
// Calculate its SCCs
86+
let sccs: Sccs<StaticNodeIdx, StaticSccIdx> = Sccs::new(&graph);
87+
// Group statics by SCCs
88+
let mut nodes_of_sccs: IndexVec<StaticSccIdx, Vec<StaticNodeIdx>> =
89+
IndexVec::from_elem_n(Vec::new(), sccs.num_sccs());
90+
for i in graph.iter_nodes() {
91+
nodes_of_sccs[sccs.scc(i)].push(i);
92+
}
93+
let is_cyclic = |nodes_of_scc: &[StaticNodeIdx]| -> bool {
94+
match nodes_of_scc.len() {
95+
0 => false,
96+
1 => graph.successors(nodes_of_scc[0]).any(|x| x == nodes_of_scc[0]),
97+
2.. => true,
98+
}
99+
};
100+
// Emit errors for all cycles
101+
for nodes in nodes_of_sccs.iter_mut().filter(|nodes| is_cyclic(nodes)) {
102+
// We sort the nodes by their Span to have consistent error line numbers
103+
nodes.sort_by_key(|node| tcx.def_span(statics[node.index()]));
104+
105+
let head_def = statics[nodes[0].index()];
106+
let head_span = tcx.def_span(head_def);
107+
108+
tcx.dcx().emit_err(errors::StaticInitializerCyclic {
109+
span: head_span,
110+
labels: nodes.iter().map(|&n| tcx.def_span(statics[n.index()])).collect(),
111+
head: &tcx.def_path_str(head_def),
112+
target: &tcx.sess.target.llvm_target,
113+
});
114+
}
115+
}

compiler/rustc_monomorphize/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed;
1616

1717
mod collector;
1818
mod errors;
19+
mod graph_checks;
1920
mod mono_checks;
2021
mod partitioning;
2122
mod util;

0 commit comments

Comments
 (0)