1
Fork 0

Fix unsafe_op_in_unsafe_fn in compiler

This commit is contained in:
Michael Goulet 2024-07-14 14:27:57 -04:00
parent 71eb49c318
commit 28503d69ac
15 changed files with 386 additions and 311 deletions

View file

@ -627,7 +627,7 @@ impl Step for Size {
#[inline] #[inline]
unsafe fn forward_unchecked(start: Self, count: usize) -> Self { unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
Self::from_bytes(u64::forward_unchecked(start.bytes(), count)) Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) })
} }
#[inline] #[inline]
@ -642,7 +642,7 @@ impl Step for Size {
#[inline] #[inline]
unsafe fn backward_unchecked(start: Self, count: usize) -> Self { unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
Self::from_bytes(u64::backward_unchecked(start.bytes(), count)) Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) })
} }
} }

View file

@ -21,14 +21,16 @@ pub(crate) unsafe fn codegen(
) { ) {
let llcx = &*module_llvm.llcx; let llcx = &*module_llvm.llcx;
let llmod = module_llvm.llmod(); let llmod = module_llvm.llmod();
let usize = match tcx.sess.target.pointer_width { let usize = unsafe {
match tcx.sess.target.pointer_width {
16 => llvm::LLVMInt16TypeInContext(llcx), 16 => llvm::LLVMInt16TypeInContext(llcx),
32 => llvm::LLVMInt32TypeInContext(llcx), 32 => llvm::LLVMInt32TypeInContext(llcx),
64 => llvm::LLVMInt64TypeInContext(llcx), 64 => llvm::LLVMInt64TypeInContext(llcx),
tws => bug!("Unsupported target word size for int: {}", tws), tws => bug!("Unsupported target word size for int: {}", tws),
}
}; };
let i8 = llvm::LLVMInt8TypeInContext(llcx); let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) };
let i8p = llvm::LLVMPointerTypeInContext(llcx, 0); let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) };
if kind == AllocatorKind::Default { if kind == AllocatorKind::Default {
for method in ALLOCATOR_METHODS { for method in ALLOCATOR_METHODS {
@ -73,6 +75,7 @@ pub(crate) unsafe fn codegen(
true, true,
); );
unsafe {
// __rust_alloc_error_handler_should_panic // __rust_alloc_error_handler_should_panic
let name = OomStrategy::SYMBOL; let name = OomStrategy::SYMBOL;
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
@ -90,6 +93,7 @@ pub(crate) unsafe fn codegen(
} }
let llval = llvm::LLVMConstInt(i8, 0, False); let llval = llvm::LLVMConstInt(i8, 0, False);
llvm::LLVMSetInitializer(ll_g, llval); llvm::LLVMSetInitializer(ll_g, llval);
}
if tcx.sess.opts.debuginfo != DebugInfo::None { if tcx.sess.opts.debuginfo != DebugInfo::None {
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);

View file

@ -727,7 +727,7 @@ pub unsafe fn optimize_thin_module(
// into that context. One day, however, we may do this for upstream // into that context. One day, however, we may do this for upstream
// crates but for locally codegened modules we may be able to reuse // crates but for locally codegened modules we may be able to reuse
// that LLVM Context and Module. // that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llcx = unsafe { llvm::LLVMRustContextCreate(cgcx.fewer_names) };
let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _; let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _;
let mut module = ModuleCodegen { let mut module = ModuleCodegen {
module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) },
@ -750,7 +750,9 @@ pub unsafe fn optimize_thin_module(
{ {
let _timer = let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { if unsafe {
!llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target)
} {
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
} }
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
@ -760,7 +762,8 @@ pub unsafe fn optimize_thin_module(
let _timer = cgcx let _timer = cgcx
.prof .prof
.generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { if unsafe { !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) }
{
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
} }
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
@ -770,7 +773,8 @@ pub unsafe fn optimize_thin_module(
let _timer = cgcx let _timer = cgcx
.prof .prof
.generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { if unsafe { !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) }
{
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
} }
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
@ -779,7 +783,9 @@ pub unsafe fn optimize_thin_module(
{ {
let _timer = let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { if unsafe {
!llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target)
} {
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
} }
save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); save_temp_bitcode(cgcx, &module, "thin-lto-after-import");

View file

@ -46,13 +46,15 @@ pub unsafe extern "C" fn selfprofile_before_pass_callback(
pass_name: *const c_char, pass_name: *const c_char,
ir_name: *const c_char, ir_name: *const c_char,
) { ) {
unsafe {
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8");
let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8");
llvm_self_profiler.before_pass_callback(pass_name, ir_name); llvm_self_profiler.before_pass_callback(pass_name, ir_name);
} }
}
pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) { pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) {
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); let llvm_self_profiler = unsafe { &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>) };
llvm_self_profiler.after_pass_callback(); llvm_self_profiler.after_pass_callback();
} }

View file

@ -428,9 +428,10 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
if user.is_null() { if user.is_null() {
return; return;
} }
let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)); let (cgcx, dcx) =
unsafe { *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)) };
match llvm::diagnostic::Diagnostic::unpack(info) { match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } {
llvm::diagnostic::InlineAsm(inline) => { llvm::diagnostic::InlineAsm(inline) => {
report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source); report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
} }
@ -454,14 +455,14 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
}); });
} }
llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => { llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => {
let message = llvm::build_string(|s| { let message = llvm::build_string(|s| unsafe {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
}) })
.expect("non-UTF8 diagnostic"); .expect("non-UTF8 diagnostic");
dcx.emit_warn(FromLlvmDiag { message }); dcx.emit_warn(FromLlvmDiag { message });
} }
llvm::diagnostic::Unsupported(diagnostic_ref) => { llvm::diagnostic::Unsupported(diagnostic_ref) => {
let message = llvm::build_string(|s| { let message = llvm::build_string(|s| unsafe {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
}) })
.expect("non-UTF8 diagnostic"); .expect("non-UTF8 diagnostic");
@ -564,7 +565,8 @@ pub(crate) unsafe fn llvm_optimize(
let llvm_plugins = config.llvm_plugins.join(","); let llvm_plugins = config.llvm_plugins.join(",");
let result = llvm::LLVMRustOptimize( let result = unsafe {
llvm::LLVMRustOptimize(
module.module_llvm.llmod(), module.module_llvm.llmod(),
&*module.module_llvm.tm, &*module.module_llvm.tm,
to_pass_builder_opt_level(opt_level), to_pass_builder_opt_level(opt_level),
@ -594,7 +596,8 @@ pub(crate) unsafe fn llvm_optimize(
extra_passes.len(), extra_passes.len(),
llvm_plugins.as_ptr().cast(), llvm_plugins.as_ptr().cast(),
llvm_plugins.len(), llvm_plugins.len(),
); )
};
result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses))
} }
@ -617,7 +620,7 @@ pub(crate) unsafe fn optimize(
if config.emit_no_opt_bc { if config.emit_no_opt_bc {
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
let out = path_to_c_string(&out); let out = path_to_c_string(&out);
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) };
} }
if let Some(opt_level) = config.opt_level { if let Some(opt_level) = config.opt_level {
@ -627,7 +630,7 @@ pub(crate) unsafe fn optimize(
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
_ => llvm::OptStage::PreLinkNoLTO, _ => llvm::OptStage::PreLinkNoLTO,
}; };
return llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage); return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) };
} }
Ok(()) Ok(())
} }
@ -692,11 +695,13 @@ pub(crate) unsafe fn codegen(
where where
F: FnOnce(&'ll mut PassManager<'ll>) -> R, F: FnOnce(&'ll mut PassManager<'ll>) -> R,
{ {
unsafe {
let cpm = llvm::LLVMCreatePassManager(); let cpm = llvm::LLVMCreatePassManager();
llvm::LLVMAddAnalysisPasses(tm, cpm); llvm::LLVMAddAnalysisPasses(tm, cpm);
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
f(cpm) f(cpm)
} }
}
// Two things to note: // Two things to note:
// - If object files are just LLVM bitcode we write bitcode, copy it to // - If object files are just LLVM bitcode we write bitcode, copy it to
@ -757,9 +762,11 @@ pub(crate) unsafe fn codegen(
let _timer = cgcx let _timer = cgcx
.prof .prof
.generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name);
unsafe {
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
} }
} }
}
if config.emit_ir { if config.emit_ir {
let _timer = let _timer =
@ -793,7 +800,8 @@ pub(crate) unsafe fn codegen(
cursor.position() as size_t cursor.position() as size_t
} }
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback); let result =
unsafe { llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback) };
if result == llvm::LLVMRustResult::Success { if result == llvm::LLVMRustResult::Success {
record_artifact_size(&cgcx.prof, "llvm_ir", &out); record_artifact_size(&cgcx.prof, "llvm_ir", &out);
@ -812,10 +820,11 @@ pub(crate) unsafe fn codegen(
// binaries. So we must clone the module to produce the asm output // binaries. So we must clone the module to produce the asm output
// if we are also producing object code. // if we are also producing object code.
let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj {
llvm::LLVMCloneModule(llmod) unsafe { llvm::LLVMCloneModule(llmod) }
} else { } else {
llmod llmod
}; };
unsafe {
with_codegen(tm, llmod, config.no_builtins, |cpm| { with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file( write_output_file(
dcx, dcx,
@ -829,6 +838,7 @@ pub(crate) unsafe fn codegen(
) )
})?; })?;
} }
}
match config.emit_obj { match config.emit_obj {
EmitObj::ObjectCode(_) => { EmitObj::ObjectCode(_) => {
@ -851,6 +861,7 @@ pub(crate) unsafe fn codegen(
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
}; };
unsafe {
with_codegen(tm, llmod, config.no_builtins, |cpm| { with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file( write_output_file(
dcx, dcx,
@ -864,6 +875,7 @@ pub(crate) unsafe fn codegen(
) )
})?; })?;
} }
}
EmitObj::Bitcode => { EmitObj::Bitcode => {
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
@ -1013,6 +1025,7 @@ unsafe fn embed_bitcode(
// reason (see issue #90326 for historical background). // reason (see issue #90326 for historical background).
let is_aix = target_is_aix(cgcx); let is_aix = target_is_aix(cgcx);
let is_apple = target_is_apple(cgcx); let is_apple = target_is_apple(cgcx);
unsafe {
if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") { if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") {
// We don't need custom section flags, create LLVM globals. // We don't need custom section flags, create LLVM globals.
let llconst = common::bytes_in_context(llcx, bitcode); let llconst = common::bytes_in_context(llcx, bitcode);
@ -1053,6 +1066,7 @@ unsafe fn embed_bitcode(
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
} }
} }
}
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`. // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
// This is required to satisfy `dllimport` references to static data in .rlibs // This is required to satisfy `dllimport` references to static data in .rlibs

View file

@ -120,7 +120,7 @@ pub unsafe fn create_module<'ll>(
) -> &'ll llvm::Module { ) -> &'ll llvm::Module {
let sess = tcx.sess; let sess = tcx.sess;
let mod_name = SmallCStr::new(mod_name); let mod_name = SmallCStr::new(mod_name);
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
let mut target_data_layout = sess.target.data_layout.to_string(); let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version(); let llvm_version = llvm_util::get_version();
@ -153,10 +153,13 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults. // Ensure the data-layout values hardcoded remain the defaults.
{ {
let tm = crate::back::write::create_informational_target_machine(tcx.sess); let tm = crate::back::write::create_informational_target_machine(tcx.sess);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
}
let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod); let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) };
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) let llvm_data_layout =
str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes())
.expect("got a non-UTF8 data-layout from LLVM"); .expect("got a non-UTF8 data-layout from LLVM");
if target_data_layout != llvm_data_layout { if target_data_layout != llvm_data_layout {
@ -170,40 +173,53 @@ pub unsafe fn create_module<'ll>(
} }
let data_layout = SmallCStr::new(&target_data_layout); let data_layout = SmallCStr::new(&target_data_layout);
unsafe {
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
}
let llvm_target = SmallCStr::new(&sess.target.llvm_target); let llvm_target = SmallCStr::new(&sess.target.llvm_target);
unsafe {
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
}
let reloc_model = sess.relocation_model(); let reloc_model = sess.relocation_model();
if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) { if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) {
unsafe {
llvm::LLVMRustSetModulePICLevel(llmod); llvm::LLVMRustSetModulePICLevel(llmod);
}
// PIE is potentially more effective than PIC, but can only be used in executables. // PIE is potentially more effective than PIC, but can only be used in executables.
// If all our outputs are executables, then we can relax PIC to PIE. // If all our outputs are executables, then we can relax PIC to PIE.
if reloc_model == RelocModel::Pie if reloc_model == RelocModel::Pie
|| tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable) || tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable)
{ {
unsafe {
llvm::LLVMRustSetModulePIELevel(llmod); llvm::LLVMRustSetModulePIELevel(llmod);
} }
} }
}
// Linking object files with different code models is undefined behavior // Linking object files with different code models is undefined behavior
// because the compiler would have to generate additional code (to span // because the compiler would have to generate additional code (to span
// longer jumps) if a larger code model is used with a smaller one. // longer jumps) if a larger code model is used with a smaller one.
// //
// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. // See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323.
unsafe {
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model()));
}
// If skipping the PLT is enabled, we need to add some module metadata // If skipping the PLT is enabled, we need to add some module metadata
// to ensure intrinsic calls don't use it. // to ensure intrinsic calls don't use it.
if !sess.needs_plt() { if !sess.needs_plt() {
let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
} }
}
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Override, llvm::LLVMModFlagBehavior::Override,
@ -211,10 +227,12 @@ pub unsafe fn create_module<'ll>(
1, 1,
); );
} }
}
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Override, llvm::LLVMModFlagBehavior::Override,
@ -222,15 +240,19 @@ pub unsafe fn create_module<'ll>(
1, 1,
); );
} }
}
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() { if sess.is_sanitizer_kcfi_enabled() {
let kcfi = c"kcfi".as_ptr().cast(); let kcfi = c"kcfi".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
} }
}
// Control Flow Guard is currently only supported by the MSVC linker on Windows. // Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc { if sess.target.is_like_msvc {
unsafe {
match sess.opts.cg.control_flow_guard { match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {} CFGuard::Disabled => {}
CFGuard::NoChecks => { CFGuard::NoChecks => {
@ -253,9 +275,11 @@ pub unsafe fn create_module<'ll>(
} }
} }
} }
}
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
if sess.target.arch == "aarch64" { if sess.target.arch == "aarch64" {
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Min, llvm::LLVMModFlagBehavior::Min,
@ -281,6 +305,7 @@ pub unsafe fn create_module<'ll>(
c"sign-return-address-with-bkey".as_ptr().cast(), c"sign-return-address-with-bkey".as_ptr().cast(),
u32::from(pac_opts.key == PAuthKey::B), u32::from(pac_opts.key == PAuthKey::B),
); );
}
} else { } else {
bug!( bug!(
"branch-protection used on non-AArch64 target; \ "branch-protection used on non-AArch64 target; \
@ -291,23 +316,28 @@ pub unsafe fn create_module<'ll>(
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Override, llvm::LLVMModFlagBehavior::Override,
c"cf-protection-branch".as_ptr().cast(), c"cf-protection-branch".as_ptr().cast(),
1, 1,
) );
}
} }
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Override, llvm::LLVMModFlagBehavior::Override,
c"cf-protection-return".as_ptr().cast(), c"cf-protection-return".as_ptr().cast(),
1, 1,
) );
}
} }
if sess.opts.unstable_opts.virtual_function_elimination { if sess.opts.unstable_opts.virtual_function_elimination {
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Error, llvm::LLVMModFlagBehavior::Error,
@ -315,9 +345,11 @@ pub unsafe fn create_module<'ll>(
1, 1,
); );
} }
}
// Set module flag to enable Windows EHCont Guard (/guard:ehcont). // Set module flag to enable Windows EHCont Guard (/guard:ehcont).
if sess.opts.unstable_opts.ehcont_guard { if sess.opts.unstable_opts.ehcont_guard {
unsafe {
llvm::LLVMRustAddModuleFlagU32( llvm::LLVMRustAddModuleFlagU32(
llmod, llmod,
llvm::LLVMModFlagBehavior::Warning, llvm::LLVMModFlagBehavior::Warning,
@ -325,6 +357,7 @@ pub unsafe fn create_module<'ll>(
1, 1,
) )
} }
}
// Insert `llvm.ident` metadata. // Insert `llvm.ident` metadata.
// //
@ -333,16 +366,20 @@ pub unsafe fn create_module<'ll>(
#[allow(clippy::option_env_unwrap)] #[allow(clippy::option_env_unwrap)]
let rustc_producer = let rustc_producer =
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
let name_metadata = llvm::LLVMMDStringInContext( let name_metadata = unsafe {
llvm::LLVMMDStringInContext(
llcx, llcx,
rustc_producer.as_ptr().cast(), rustc_producer.as_ptr().cast(),
rustc_producer.as_bytes().len() as c_uint, rustc_producer.as_bytes().len() as c_uint,
); )
};
unsafe {
llvm::LLVMAddNamedMetadataOperand( llvm::LLVMAddNamedMetadataOperand(
llmod, llmod,
c"llvm.ident".as_ptr(), c"llvm.ident".as_ptr(),
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
); );
}
// Emit RISC-V specific target-abi metadata // Emit RISC-V specific target-abi metadata
// to workaround lld as the LTO plugin not // to workaround lld as the LTO plugin not
@ -351,6 +388,7 @@ pub unsafe fn create_module<'ll>(
// If llvm_abiname is empty, emit nothing. // If llvm_abiname is empty, emit nothing.
let llvm_abiname = &sess.target.options.llvm_abiname; let llvm_abiname = &sess.target.options.llvm_abiname;
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
unsafe {
llvm::LLVMRustAddModuleFlagString( llvm::LLVMRustAddModuleFlagString(
llmod, llmod,
llvm::LLVMModFlagBehavior::Error, llvm::LLVMModFlagBehavior::Error,
@ -359,6 +397,7 @@ pub unsafe fn create_module<'ll>(
llvm_abiname.len(), llvm_abiname.len(),
); );
} }
}
// Add module flags specified via -Z llvm_module_flag // Add module flags specified via -Z llvm_module_flag
for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
@ -375,7 +414,7 @@ pub unsafe fn create_module<'ll>(
// We already checked this during option parsing // We already checked this during option parsing
_ => unreachable!(), _ => unreachable!(),
}; };
llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
} }
llmod llmod

View file

@ -216,7 +216,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
module: &ModuleCodegen<Self::Module>, module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig, config: &ModuleConfig,
) -> Result<(), FatalError> { ) -> Result<(), FatalError> {
back::write::optimize(cgcx, dcx, module, config) unsafe { back::write::optimize(cgcx, dcx, module, config) }
} }
fn optimize_fat( fn optimize_fat(
cgcx: &CodegenContext<Self>, cgcx: &CodegenContext<Self>,
@ -230,7 +230,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
cgcx: &CodegenContext<Self>, cgcx: &CodegenContext<Self>,
thin: ThinModule<Self>, thin: ThinModule<Self>,
) -> Result<ModuleCodegen<Self::Module>, FatalError> { ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::lto::optimize_thin_module(thin, cgcx) unsafe { back::lto::optimize_thin_module(thin, cgcx) }
} }
unsafe fn codegen( unsafe fn codegen(
cgcx: &CodegenContext<Self>, cgcx: &CodegenContext<Self>,
@ -238,7 +238,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
module: ModuleCodegen<Self::Module>, module: ModuleCodegen<Self::Module>,
config: &ModuleConfig, config: &ModuleConfig,
) -> Result<CompiledModule, FatalError> { ) -> Result<CompiledModule, FatalError> {
back::write::codegen(cgcx, dcx, module, config) unsafe { back::write::codegen(cgcx, dcx, module, config) }
} }
fn prepare_thin( fn prepare_thin(
module: ModuleCodegen<Self::Module>, module: ModuleCodegen<Self::Module>,

View file

@ -40,7 +40,7 @@ impl<'ll> OptimizationDiagnostic<'ll> {
let mut filename = None; let mut filename = None;
let pass_name = super::build_string(|pass_name| { let pass_name = super::build_string(|pass_name| {
message = super::build_string(|message| { message = super::build_string(|message| {
filename = super::build_string(|filename| { filename = super::build_string(|filename| unsafe {
super::LLVMRustUnpackOptimizationDiagnostic( super::LLVMRustUnpackOptimizationDiagnostic(
di, di,
pass_name, pass_name,
@ -91,7 +91,7 @@ impl SrcMgrDiagnostic {
let mut ranges = [0; 8]; let mut ranges = [0; 8];
let mut num_ranges = ranges.len() / 2; let mut num_ranges = ranges.len() / 2;
let message = super::build_string(|message| { let message = super::build_string(|message| {
buffer = super::build_string(|buffer| { buffer = super::build_string(|buffer| unsafe {
have_source = super::LLVMRustUnpackSMDiagnostic( have_source = super::LLVMRustUnpackSMDiagnostic(
diag, diag,
message, message,
@ -134,7 +134,9 @@ impl InlineAsmDiagnostic {
let mut message = None; let mut message = None;
let mut level = super::DiagnosticLevel::Error; let mut level = super::DiagnosticLevel::Error;
unsafe {
super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
}
InlineAsmDiagnostic { InlineAsmDiagnostic {
level, level,
@ -146,7 +148,8 @@ impl InlineAsmDiagnostic {
unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self { unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self {
let mut cookie = 0; let mut cookie = 0;
let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)); let smdiag =
unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) };
InlineAsmDiagnostic { InlineAsmDiagnostic {
level: smdiag.level, level: smdiag.level,
cookie: cookie.into(), cookie: cookie.into(),
@ -170,8 +173,9 @@ pub enum Diagnostic<'ll> {
impl<'ll> Diagnostic<'ll> { impl<'ll> Diagnostic<'ll> {
pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
use super::DiagnosticKind as Dk; use super::DiagnosticKind as Dk;
let kind = super::LLVMRustGetDiagInfoKind(di);
unsafe {
let kind = super::LLVMRustGetDiagInfoKind(di);
match kind { match kind {
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
@ -211,3 +215,4 @@ impl<'ll> Diagnostic<'ll> {
} }
} }
} }
}

View file

@ -49,13 +49,17 @@ unsafe fn configure_llvm(sess: &Session) {
let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
let mut llvm_args = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1);
unsafe {
llvm::LLVMRustInstallErrorHandlers(); llvm::LLVMRustInstallErrorHandlers();
}
// On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
// box for the purpose of launching a debugger. However, on CI this will // box for the purpose of launching a debugger. However, on CI this will
// cause it to hang until it times out, which can take several hours. // cause it to hang until it times out, which can take several hours.
if std::env::var_os("CI").is_some() { if std::env::var_os("CI").is_some() {
unsafe {
llvm::LLVMRustDisableSystemDialogsOnCrash(); llvm::LLVMRustDisableSystemDialogsOnCrash();
} }
}
fn llvm_arg_to_arg_name(full_arg: &str) -> &str { fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("") full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
@ -124,12 +128,12 @@ unsafe fn configure_llvm(sess: &Session) {
} }
if sess.opts.unstable_opts.llvm_time_trace { if sess.opts.unstable_opts.llvm_time_trace {
llvm::LLVMRustTimeTraceProfilerInitialize(); unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() };
} }
rustc_llvm::initialize_available_targets(); rustc_llvm::initialize_available_targets();
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); unsafe { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()) };
} }
pub fn time_trace_profiler_finish(file_name: &Path) { pub fn time_trace_profiler_finish(file_name: &Path) {
@ -442,8 +446,8 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
.unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) {
let out = &mut *(out as *mut &mut String); let out = unsafe { &mut *(out as *mut &mut String) };
let bytes = slice::from_raw_parts(string as *const u8, len); let bytes = unsafe { slice::from_raw_parts(string as *const u8, len) };
write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap();
} }
unsafe { unsafe {

View file

@ -108,8 +108,8 @@ impl CodegenCx<'_, '_> {
llval: &llvm::Value, llval: &llvm::Value,
is_declaration: bool, is_declaration: bool,
) -> bool { ) -> bool {
let linkage = llvm::LLVMRustGetLinkage(llval); let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
let visibility = llvm::LLVMRustGetVisibility(llval); let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
return true; return true;
@ -145,8 +145,8 @@ impl CodegenCx<'_, '_> {
} }
// Thread-local variables generally don't support copy relocations. // Thread-local variables generally don't support copy relocations.
let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) }
.is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True);
if is_thread_local_var { if is_thread_local_var {
return false; return false;
} }

View file

@ -72,7 +72,7 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
B::optimize_fat(cgcx, &mut module)?; B::optimize_fat(cgcx, &mut module)?;
Ok(module) Ok(module)
} }
LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), LtoModuleCodegen::Thin(thin) => unsafe { B::optimize_thin(cgcx, thin) },
} }
} }

View file

@ -33,7 +33,7 @@ pub unsafe extern "C" fn LLVMRustStringWriteImpl(
ptr: *const c_char, ptr: *const c_char,
size: size_t, size: size_t,
) { ) {
let slice = slice::from_raw_parts(ptr as *const u8, size); let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) };
sr.bytes.borrow_mut().extend_from_slice(slice); sr.bytes.borrow_mut().extend_from_slice(slice);
} }

View file

@ -67,7 +67,7 @@ fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
#[inline] #[inline]
unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> { unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
&*(context as *const ImplicitCtxt<'a, 'tcx>) unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) }
} }
/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.

View file

@ -89,13 +89,13 @@ cfg_match! {
let ptr = src_bytes.as_ptr() as *const __m128i; let ptr = src_bytes.as_ptr() as *const __m128i;
// We don't know if the pointer is aligned to 16 bytes, so we // We don't know if the pointer is aligned to 16 bytes, so we
// use `loadu`, which supports unaligned loading. // use `loadu`, which supports unaligned loading.
let chunk = _mm_loadu_si128(ptr.add(chunk_index)); let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) };
// For character in the chunk, see if its byte value is < 0, which // For character in the chunk, see if its byte value is < 0, which
// indicates that it's part of a UTF-8 char. // indicates that it's part of a UTF-8 char.
let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) };
// Create a bit mask from the comparison results. // Create a bit mask from the comparison results.
let multibyte_mask = _mm_movemask_epi8(multibyte_test); let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) };
// If the bit mask is all zero, we only have ASCII chars here: // If the bit mask is all zero, we only have ASCII chars here:
if multibyte_mask == 0 { if multibyte_mask == 0 {
@ -104,19 +104,19 @@ cfg_match! {
// Check if there are any control characters in the chunk. All // Check if there are any control characters in the chunk. All
// control characters that we can encounter at this point have a // control characters that we can encounter at this point have a
// byte value less than 32 or ... // byte value less than 32 or ...
let control_char_test0 = _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)); let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) };
let control_char_mask0 = _mm_movemask_epi8(control_char_test0); let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) };
// ... it's the ASCII 'DEL' character with a value of 127. // ... it's the ASCII 'DEL' character with a value of 127.
let control_char_test1 = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)); let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) };
let control_char_mask1 = _mm_movemask_epi8(control_char_test1); let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) };
let control_char_mask = control_char_mask0 | control_char_mask1; let control_char_mask = control_char_mask0 | control_char_mask1;
if control_char_mask != 0 { if control_char_mask != 0 {
// Check for newlines in the chunk // Check for newlines in the chunk
let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
let newlines_mask = _mm_movemask_epi8(newlines_test); let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
if control_char_mask == newlines_mask { if control_char_mask == newlines_mask {
// All control characters are newlines, record them // All control characters are newlines, record them

View file

@ -2001,6 +2001,7 @@ impl<'a> Builder<'a> {
// FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all
// of the individual lints are satisfied. // of the individual lints are satisfied.
rustflags.arg("-Wkeyword_idents_2024"); rustflags.arg("-Wkeyword_idents_2024");
rustflags.arg("-Wunsafe_op_in_unsafe_fn");
} }
if self.config.rust_frame_pointers { if self.config.rust_frame_pointers {