1use std::any::Any;
5use std::cell::OnceCell;
6use std::ffi::CStr;
7use std::marker::PhantomData;
8use std::mem::ManuallyDrop;
9use std::path::PathBuf;
10use std::ptr;
11
12use rustc_ast::expand::allocator::AllocatorMethod;
13use rustc_codegen_ssa::back::lto::ThinModule;
14use rustc_codegen_ssa::back::write::{
15 CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,
16 TargetMachineFactoryFn, ThinLtoInput,
17};
18use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
19use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig};
20use rustc_data_structures::profiling::SelfProfilerRef;
21use rustc_errors::{DiagCtxt, DiagCtxtHandle};
22use rustc_metadata::EncodedMetadata;
23use rustc_middle::dep_graph::{WorkProduct, WorkProductMap};
24use rustc_middle::ty::TyCtxt;
25use rustc_session::config::{LtoCli, OptLevel, OutputFilenames, PrintKind, PrintRequest};
26use rustc_session::{
27 BorrowedIncrCompSession, CodegenBackendInit, EarlySession, IncrCompSession, Session,
28};
29use rustc_span::{Symbol, sym};
30use rustc_target::spec::{RelocModel, SplitDebuginfo, TlsModel};
31
32use crate::back::owned_target_machine::OwnedTargetMachine;
33use crate::back::write::{create_informational_target_machine, create_target_machine};
34use crate::context::{self, SimpleCx};
35use crate::llvm::{self, ToLlvmBool};
36use crate::llvm_util::{self, target_config};
37use crate::{allocator, back, base};
38
39#[derive(#[automatically_derived]impl ::core::clone::Clone for LlvmCodegenBackend {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
LlvmCodegenBackend(::core::clone::Clone::clone(&self.0))
}
}Clone)]
40pub struct LlvmCodegenBackend(());
41
42struct TimeTraceProfiler {}
43
44impl TimeTraceProfiler {
45 fn new() -> Self {
46 unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }
47 TimeTraceProfiler {}
48 }
49}
50
51impl Drop for TimeTraceProfiler {
52 fn drop(&mut self) {
53 unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }
54 }
55}
56
57impl ExtraBackendMethods for LlvmCodegenBackend {
58 type Module = ModuleLlvm;
59
60 fn codegen_allocator<'tcx>(
61 &self,
62 tcx: TyCtxt<'tcx>,
63 module_name: &str,
64 methods: &[AllocatorMethod],
65 ) -> ModuleLlvm {
66 let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
67 module_llvm.with_module_refs(|ModuleRefs { llcx, llmod, .. }| {
68 let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size());
69 unsafe { allocator::codegen(tcx, cx, module_name, methods) };
70 });
71 module_llvm
72 }
73 fn compile_codegen_unit(
74 &self,
75 tcx: TyCtxt<'_>,
76 cgu_name: Symbol,
77 bitcode_needed: bool,
78 ) -> (ModuleCodegen<ModuleLlvm>, u64) {
79 base::compile_codegen_unit(tcx, cgu_name, bitcode_needed)
80 }
81}
82
83impl WriteBackendMethods for LlvmCodegenBackend {
84 type Module = ModuleLlvm;
85 type ModuleBuffer = back::lto::ModuleBuffer;
86 type TargetMachine = OwnedTargetMachine;
87 type ThinData = back::lto::ThinData;
88
89 fn thread_profiler() -> Box<dyn Any> {
90 Box::new(TimeTraceProfiler::new())
91 }
92 fn target_machine_factory(&self, sess: &Session) -> TargetMachineFactoryFn<Self> {
93 back::write::target_machine_factory(sess, sess.opts.optimize)
94 }
95 fn optimize_and_codegen_fat_lto(
96 sess: &Session,
97 cgcx: &CodegenContext,
98 shared_emitter: &SharedEmitter,
99 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
100 exported_symbols_for_lto: &[String],
101 each_linked_rlib_for_lto: &[PathBuf],
102 modules: Vec<FatLtoInput<Self>>,
103 ) -> CompiledModule {
104 let module = back::lto::run_fat(
105 cgcx,
106 &sess.prof,
107 shared_emitter,
108 tm_factory,
109 exported_symbols_for_lto,
110 each_linked_rlib_for_lto,
111 modules,
112 );
113
114 let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
115 let dcx = dcx.handle();
116 back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &module, false);
117
118 back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config)
119 }
120 fn run_thin_lto(
121 cgcx: &CodegenContext,
122 prof: &SelfProfilerRef,
123 incr_comp_session: Option<&BorrowedIncrCompSession>,
124 dcx: DiagCtxtHandle<'_>,
125 exported_symbols_for_lto: &[String],
126 each_linked_rlib_for_lto: &[PathBuf],
127 modules: Vec<ThinLtoInput<Self>>,
128 ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
129 back::lto::run_thin(
130 cgcx,
131 prof,
132 incr_comp_session,
133 dcx,
134 exported_symbols_for_lto,
135 each_linked_rlib_for_lto,
136 modules,
137 )
138 }
139 fn optimize(
140 cgcx: &CodegenContext,
141 prof: &SelfProfilerRef,
142 shared_emitter: &SharedEmitter,
143 module: &mut ModuleCodegen<Self::Module>,
144 config: &ModuleConfig,
145 ) {
146 back::write::optimize(cgcx, prof, shared_emitter, module, config);
147 }
148 fn optimize_and_codegen_thin(
149 cgcx: &CodegenContext,
150 prof: &SelfProfilerRef,
151 shared_emitter: &SharedEmitter,
152 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
153 thin: ThinModule<Self>,
154 ) -> CompiledModule {
155 back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin)
156 }
157 fn codegen(
158 cgcx: &CodegenContext,
159 prof: &SelfProfilerRef,
160 shared_emitter: &SharedEmitter,
161 module: ModuleCodegen<Self::Module>,
162 config: &ModuleConfig,
163 ) -> CompiledModule {
164 back::write::codegen(cgcx, prof, shared_emitter, module, config)
165 }
166 fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer {
167 module.with_module_refs(|ModuleRefs { llmod, .. }| {
168 back::lto::ModuleBuffer::new(llmod, is_thin)
169 })
170 }
171}
172
173impl LlvmCodegenBackend {
174 pub fn new() -> Box<dyn CodegenBackend> {
175 Box::new(LlvmCodegenBackend(()))
176 }
177}
178
179impl CodegenBackend for LlvmCodegenBackend {
180 fn name(&self) -> &'static str {
181 "llvm"
182 }
183
184 fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit {
185 llvm_util::init(sess); let global_backend_features =
188 llvm_util::global_llvm_features(sess, false);
189
190 {
194 use rustc_session::config::AutoDiff;
195
196 use crate::back::lto::enable_autodiff_settings;
197 if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
198 match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
199 Ok(_) => {}
200 Err(llvm::EnzymeLibraryError::NotFound { err }) => {
201 sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err });
202 }
203 Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
204 sess.dcx()
205 .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err });
206 }
207 }
208 enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
209 }
210 }
211
212 {
215 match llvm::TpdeWrapper::get_or_init(
216 &sess.opts.sysroot,
217 &sess.opts.unstable_opts.llvm_tpde,
218 ) {
219 Ok(_) => {}
220 Err(llvm::TpdeLibraryError::NotFound { err }) => {
221 sess.dcx().emit_fatal(crate::diagnostics::TpdeComponentMissing { err });
222 }
223 Err(llvm::TpdeLibraryError::LoadFailed { err }) => {
224 sess.dcx().emit_fatal(crate::diagnostics::TpdeComponentUnavailable { err });
225 }
226 }
227
228 if sess.opts.unstable_opts.llvm_tpde.is_some() {
229 if !#[allow(non_exhaustive_omitted_patterns)] match sess.opts.optimize {
OptLevel::No | OptLevel::Less => true,
_ => false,
}matches!(sess.opts.optimize, OptLevel::No | OptLevel::Less) {
230 sess.dcx().emit_warn(crate::diagnostics::TpdeHighOptLevel);
231 }
232
233 if sess.target.requires_lto
234 || !#[allow(non_exhaustive_omitted_patterns)] match sess.early_lto() {
LtoCli::No | LtoCli::Unspecified => true,
_ => false,
}matches!(sess.early_lto(), LtoCli::No | LtoCli::Unspecified)
235 {
236 sess.dcx().emit_fatal(crate::diagnostics::TpdeLtoUsed);
237 }
238
239 #[allow(rustc::bad_opt_access)]
241 if sess.opts.cg.split_debuginfo.unwrap_or(sess.target.split_debuginfo)
242 != SplitDebuginfo::Off
243 {
244 sess.dcx().emit_fatal(crate::diagnostics::TpdeSplitDebugInfoUsed);
245 }
246 }
247 }
248
249 let replaced_intrinsics = {
251 #[rustfmt::skip]
252 let will_not_use_fallback = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::unchecked_funnel_shl, sym::unchecked_funnel_shr,
sym::carrying_mul_add, sym::carryless_mul, sym::integer_max,
sym::integer_min, sym::sin, sym::cos, sym::powf, sym::powi,
sym::sqrt, sym::exp, sym::exp2, sym::log, sym::log10,
sym::log2, sym::floor, sym::ceil, sym::trunc, sym::round,
sym::round_ties_even, sym::fma, sym::copysignf16,
sym::copysignf32, sym::copysignf64, sym::copysignf128]))vec![
253 sym::unchecked_funnel_shl,
255 sym::unchecked_funnel_shr,
256 sym::carrying_mul_add,
257 sym::carryless_mul,
258 sym::integer_max,
259 sym::integer_min,
260
261 sym::sin,
263 sym::cos,
264 sym::powf,
265 sym::powi,
266 sym::sqrt,
267 sym::exp,
268 sym::exp2,
269 sym::log,
270 sym::log10,
271 sym::log2,
272 sym::floor, sym::ceil, sym::trunc,
273 sym::round, sym::round_ties_even,
274 sym::fma,
275
276 sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128,
277 ];
278
279 will_not_use_fallback
280 };
281
282 let fallback_intrinsics = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::type_id_eq]))vec![sym::type_id_eq];
288
289 CodegenBackendInit {
290 global_backend_features,
291 replaced_intrinsics,
292 fallback_intrinsics,
293 thin_lto_supported: true,
294 }
295 }
296
297 fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
298 use std::fmt::Write;
299 match req.kind {
300 PrintKind::RelocationModels => {
301 out.write_fmt(format_args!("Available relocation models:\n"))writeln!(out, "Available relocation models:").unwrap();
302 for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {
303 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
304 }
305 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
306 }
307 PrintKind::CodeModels => {
308 out.write_fmt(format_args!("Available code models:\n"))writeln!(out, "Available code models:").unwrap();
309 for name in &["tiny", "small", "kernel", "medium", "large"] {
310 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
311 }
312 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
313 }
314 PrintKind::TlsModels => {
315 out.write_fmt(format_args!("Available TLS models:\n"))writeln!(out, "Available TLS models:").unwrap();
316 for name in TlsModel::ALL.iter().map(TlsModel::desc) {
317 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
318 }
319 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
320 }
321 PrintKind::StackProtectorStrategies => {
322 out.write_fmt(format_args!("Available stack protector strategies:\n all\n Generate stack canaries in all functions.\n\n strong\n Generate stack canaries in a function if it either:\n - has a local variable of `[T; N]` type, regardless of `T` and `N`\n - takes the address of a local variable.\n\n (Note that a local variable being borrowed is not equivalent to its\n address being taken: e.g. some borrows may be removed by optimization,\n while by-value argument passing may be implemented with reference to a\n local stack variable in the ABI.)\n\n basic\n Generate stack canaries in functions with local variables of `[T; N]`\n type, where `T` is byte-sized and `N` >= 8.\n\n none\n Do not generate stack canaries.\n\n"))writeln!(
323 out,
324 r#"Available stack protector strategies:
325 all
326 Generate stack canaries in all functions.
327
328 strong
329 Generate stack canaries in a function if it either:
330 - has a local variable of `[T; N]` type, regardless of `T` and `N`
331 - takes the address of a local variable.
332
333 (Note that a local variable being borrowed is not equivalent to its
334 address being taken: e.g. some borrows may be removed by optimization,
335 while by-value argument passing may be implemented with reference to a
336 local stack variable in the ABI.)
337
338 basic
339 Generate stack canaries in functions with local variables of `[T; N]`
340 type, where `T` is byte-sized and `N` >= 8.
341
342 none
343 Do not generate stack canaries.
344"#
345 )
346 .unwrap();
347 }
348 _other => llvm_util::print(req, out, sess),
349 }
350 }
351
352 fn print_passes(&self) {
353 llvm_util::print_passes();
354 }
355
356 fn print_version(&self) {
357 llvm_util::print_version();
358 }
359
360 fn has_zstd(&self) -> bool {
361 llvm::LLVMRustLLVMHasZstdCompression()
362 }
363
364 fn has_mnemonic(&self, sess: &Session, mnemonic: &str) -> bool {
365 llvm_util::target_has_mnemonic(sess, mnemonic)
366 }
367
368 fn target_config(&self, sess: &EarlySession) -> TargetConfig {
369 target_config(sess)
370 }
371
372 fn target_cpu(&self, sess: &Session) -> String {
373 crate::llvm_util::target_cpu(sess).to_string()
374 }
375
376 fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
377 use rustc_session::config::Offload;
378
379 if tcx.sess.opts.unstable_opts.offload.iter().any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
Offload::Device(_) => true,
_ => false,
}matches!(o, Offload::Device(_)))
380 || tcx.sess.opts.unstable_opts.offload.iter().any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
Offload::Host(_) => true,
_ => false,
}matches!(o, Offload::Host(_)))
381 {
382 match llvm::RustOffloadWrapper::get_or_init(&tcx.sess.opts.sysroot) {
383 Ok(_) => {}
384 Err(llvm::RustOffloadLibraryError::NotFound { err }) => {
385 tcx.sess
386 .dcx()
387 .emit_fatal(crate::diagnostics::RustOffloadComponentMissing { err });
388 }
389 Err(llvm::RustOffloadLibraryError::LoadFailed { err }) => {
390 tcx.sess
391 .dcx()
392 .emit_fatal(crate::diagnostics::RustOffloadComponentUnavailable { err });
393 }
394 }
395 }
396
397 Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx))
398 }
399
400 fn join_codegen(
401 &self,
402 ongoing_codegen: Box<dyn Any>,
403 sess: &Session,
404 incr_comp_session: Option<&IncrCompSession>,
405 outputs: &OutputFilenames,
406 crate_info: &CrateInfo,
407 ) -> (CompiledModules, WorkProductMap) {
408 let (compiled_modules, work_products) = ongoing_codegen
409 .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
410 .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
411 .join(sess, incr_comp_session, crate_info);
412
413 if sess.opts.unstable_opts.llvm_time_trace {
414 sess.time("llvm_dump_timing_file", || {
415 let file_name = outputs.with_extension("llvm_timings.json");
416 llvm_util::time_trace_profiler_finish(&file_name);
417 });
418 }
419
420 if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
421 let timings =
422 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap();
423 { ::std::io::_print(format_args!("{0}", timings)); };print!("{timings}");
424 }
425
426 if sess.print_llvm_stats() {
427 let stats =
428 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
429 { ::std::io::_print(format_args!("{0}", stats)); };print!("{stats}");
430 }
431
432 if let Some(out_path) = sess.print_llvm_stats_json() {
433 let llvm_stats_json =
434 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap();
435
436 if !llvm_stats_json.is_empty() {
437 if let Err(e) = std::fs::write(out_path, llvm_stats_json) {
438 sess.dcx().err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to write stats to {0}: {1}",
out_path, e))
})format!("failed to write stats to {out_path}: {e}"));
439 }
440 } else {
441 sess.dcx().warn(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("requested to print LLVM statistics to JSON file {0}, but the codegen backend did not provide any statistics",
out_path))
})format!(
442 "requested to print LLVM statistics to JSON file {out_path}, but the codegen backend \
443 did not provide any statistics",
444 ));
445 }
446 }
447
448 (compiled_modules, work_products)
449 }
450
451 fn link(
452 &self,
453 sess: &Session,
454 compiled_modules: CompiledModules,
455 crate_info: CrateInfo,
456 metadata: EncodedMetadata,
457 outputs: &OutputFilenames,
458 ) {
459 use rustc_codegen_ssa::back::link::link_binary;
460
461 use crate::back::archive::LlvmArchiveBuilderBuilder;
462
463 link_binary(
466 sess,
467 &LlvmArchiveBuilderBuilder,
468 compiled_modules,
469 crate_info,
470 metadata,
471 outputs,
472 self.name(),
473 );
474 }
475}
476
477pub struct ModuleLlvm {
478 llcx_raw: ptr::NonNull<llvm::ContextRaw>,
479 llmod_raw: ptr::NonNull<llvm::ModuleRaw>,
480
481 tm: ManuallyDrop<OwnedTargetMachine>,
484
485 pub(crate) thin_lto_buffer: OnceCell<Vec<u8>>,
490}
491
492unsafe impl Send for ModuleLlvm {}
496
497fn create_context_and_set_fewer_names(fewer_names: bool) -> ptr::NonNull<llvm::ContextRaw> {
500 unsafe {
501 let llcx_raw = llvm::LLVMContextCreate();
502 llvm::LLVMContextSetDiscardValueNames(
503 llvm::wrap_llcx(llcx_raw),
504 fewer_names.to_llvm_bool(),
505 );
506 llcx_raw
507 }
508}
509
510impl ModuleLlvm {
511 pub(crate) fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
512 unsafe {
513 let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
514 let llmod_raw =
515 context::create_module(tcx, llvm::wrap_llcx(llcx_raw), mod_name).llmod_raw();
516 ModuleLlvm {
517 llmod_raw,
518 llcx_raw,
519 tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),
520 thin_lto_buffer: OnceCell::new(),
521 }
522 }
523 }
524
525 pub(crate) fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
526 unsafe {
527 let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
528 let llmod_raw =
529 context::create_module(tcx, llvm::wrap_llcx(llcx_raw), mod_name).llmod_raw();
530 ModuleLlvm {
531 llmod_raw,
532 llcx_raw,
533 tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
534 thin_lto_buffer: OnceCell::new(),
535 }
536 }
537 }
538
539 pub(crate) fn parse(
540 cgcx: &CodegenContext,
541 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
542 name: &CStr,
543 buffer: &[u8],
544 dcx: DiagCtxtHandle<'_>,
545 ) -> Self {
546 unsafe {
547 let llcx_raw = create_context_and_set_fewer_names(cgcx.fewer_names);
548 let llmod_raw =
549 back::lto::parse_module(llvm::wrap_llcx(llcx_raw), name, buffer, dcx).llmod_raw();
550 let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()));
551
552 ModuleLlvm {
553 llmod_raw,
554 llcx_raw,
555 tm: ManuallyDrop::new(tm),
556 thin_lto_buffer: OnceCell::new(),
557 }
558 }
559 }
560
561 pub(crate) fn with_module_refs<R>(
567 &self,
568 inner_fn: impl for<'ll> FnOnce(ModuleRefs<'ll>) -> R,
569 ) -> R {
570 let llcx = unsafe { llvm::wrap_llcx(self.llcx_raw) };
571 let llmod = unsafe { llvm::wrap_llmod(llcx, self.llmod_raw) };
572 inner_fn(ModuleRefs { llcx, llmod, tm: self.tm.raw(), _ph: PhantomData })
573 }
574}
575
576impl Drop for ModuleLlvm {
577 fn drop(&mut self) {
578 unsafe {
579 ManuallyDrop::drop(&mut self.tm);
580 llvm::LLVMContextDispose(self.llcx_raw);
581 }
582 }
583}
584
585#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl<'ll>
::core::clone::TrivialClone for ModuleRefs<'ll> {
}
#[automatically_derived]impl<'ll> ::core::clone::Clone for ModuleRefs<'ll> {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<llvm::Context<'ll>>;
let _: ::core::clone::AssertParamIsClone<llvm::Module<'ll>>;
let _: ::core::clone::AssertParamIsClone<&'ll llvm::TargetMachine>;
let _:
::core::clone::AssertParamIsClone<PhantomData<fn(&'ll ())
-> &'ll ()>>;
*self
}
}Clone, #[automatically_derived]impl<'ll> ::core::marker::Copy for ModuleRefs<'ll> { }Copy)]
587pub(crate) struct ModuleRefs<'ll> {
588 pub(crate) llcx: llvm::Context<'ll>,
589 pub(crate) llmod: llvm::Module<'ll>,
590 pub(crate) tm: &'ll llvm::TargetMachine,
591 _ph: PhantomData<fn(&'ll ()) -> &'ll ()>,
596}