Skip to content

Commit c5d2aec

Browse files
committed
Refactor emitting errors to declare.rs, and use fluently-generated error messages
Create lints for deprecated and invalid intrinsics
1 parent bba9fce commit c5d2aec

File tree

13 files changed

+220
-105
lines changed

13 files changed

+220
-105
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ codegen_llvm_from_llvm_diag = {$message}
99
1010
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
1111
12+
codegen_llvm_intrinsic_signature_mismatch =
13+
intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
14+
15+
1216
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
1317
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
1418

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -304,33 +304,42 @@ impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
304304
}
305305

306306
pub(crate) enum FunctionSignature<'ll> {
307-
/// The signature is obtained directly from LLVM, and **may not match the Rust signature**
308-
Intrinsic(&'ll Type),
307+
/// This is an LLVM intrinsic, the signature is obtained directly from LLVM, and **may not match the Rust signature**
308+
LLVMSignature(llvm::Intrinsic, &'ll Type),
309+
/// This is an LLVM intrinsic, but the signature is just the Rust signature.
310+
/// FIXME: this should ideally not exist, we should be using the LLVM signature for all LLVM intrinsics
311+
RustSignature(llvm::Intrinsic, &'ll Type),
309312
/// The name starts with `llvm.`, but can't obtain the intrinsic ID. May be invalid or upgradable
310-
MaybeInvalidIntrinsic(&'ll Type),
313+
MaybeInvalid(&'ll Type),
311314
/// Just the Rust signature
312-
Rust(&'ll Type),
315+
NotIntrinsic(&'ll Type),
313316
}
314317

315318
impl<'ll> FunctionSignature<'ll> {
316319
pub(crate) fn fn_ty(&self) -> &'ll Type {
317320
match self {
318-
FunctionSignature::Intrinsic(fn_ty)
319-
| FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
320-
| FunctionSignature::Rust(fn_ty) => fn_ty,
321+
FunctionSignature::LLVMSignature(_, fn_ty)
322+
| FunctionSignature::RustSignature(_, fn_ty)
323+
| FunctionSignature::MaybeInvalid(fn_ty)
324+
| FunctionSignature::NotIntrinsic(fn_ty) => fn_ty,
325+
}
326+
}
327+
328+
pub(crate) fn intrinsic(&self) -> Option<llvm::Intrinsic> {
329+
match self {
330+
FunctionSignature::RustSignature(intrinsic, _)
331+
| FunctionSignature::LLVMSignature(intrinsic, _) => Some(*intrinsic),
332+
_ => None,
321333
}
322334
}
323335
}
324336

325337
pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
326338
fn llvm_return_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
327339
fn llvm_argument_types(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<&'ll Type>;
328-
fn llvm_type(
329-
&self,
330-
cx: &CodegenCx<'ll, 'tcx>,
331-
name: &[u8],
332-
do_verify: bool,
333-
) -> FunctionSignature<'ll>;
340+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll>;
341+
/// The normal Rust signature for this
342+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
334343
/// **If this function is an LLVM intrinsic** checks if the LLVM signature provided matches with this
335344
fn verify_intrinsic_signature(&self, cx: &CodegenCx<'ll, 'tcx>, llvm_ty: &'ll Type) -> bool;
336345

@@ -476,51 +485,35 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
476485
.all(|(rust_ty, llvm_ty)| cx.equate_ty(rust_ty, llvm_ty))
477486
}
478487

479-
fn llvm_type(
480-
&self,
481-
cx: &CodegenCx<'ll, 'tcx>,
482-
name: &[u8],
483-
do_verify: bool,
484-
) -> FunctionSignature<'ll> {
485-
let mut maybe_invalid = false;
488+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
489+
let return_ty = self.llvm_return_type(cx);
490+
let argument_tys = self.llvm_argument_types(cx);
486491

492+
if self.c_variadic {
493+
cx.type_variadic_func(&argument_tys, return_ty)
494+
} else {
495+
cx.type_func(&argument_tys, return_ty)
496+
}
497+
}
498+
499+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll> {
487500
if name.starts_with(b"llvm.") {
488501
if let Some(intrinsic) = llvm::Intrinsic::lookup(name) {
489502
if !intrinsic.is_overloaded() {
490503
// FIXME: also do this for overloaded intrinsics
491-
let llvm_fn_ty = intrinsic.get_type(cx.llcx, &[]);
492-
if do_verify {
493-
if !self.verify_intrinsic_signature(cx, llvm_fn_ty) {
494-
cx.tcx.dcx().fatal(format!(
495-
"Intrinsic signature mismatch for `{}`: expected signature `{llvm_fn_ty:?}`",
496-
str::from_utf8(name).unwrap()
497-
));
498-
}
499-
}
500-
return FunctionSignature::Intrinsic(llvm_fn_ty);
504+
FunctionSignature::LLVMSignature(intrinsic, intrinsic.get_type(cx.llcx, &[]))
505+
} else {
506+
FunctionSignature::RustSignature(intrinsic, self.rust_signature(cx))
501507
}
502508
} else {
503509
// it's one of 2 cases,
504510
// - either the base name is invalid
505511
// - it has been superseded by something else, so the intrinsic was removed entirely
506512
// to check for upgrades, we need the `llfn`, so we defer it for now
507-
maybe_invalid = true;
513+
FunctionSignature::MaybeInvalid(self.rust_signature(cx))
508514
}
509-
}
510-
511-
let return_ty = self.llvm_return_type(cx);
512-
let argument_tys = self.llvm_argument_types(cx);
513-
514-
let fn_ty = if self.c_variadic {
515-
cx.type_variadic_func(&argument_tys, return_ty)
516515
} else {
517-
cx.type_func(&argument_tys, return_ty)
518-
};
519-
520-
if maybe_invalid {
521-
FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
522-
} else {
523-
FunctionSignature::Rust(fn_ty)
516+
FunctionSignature::NotIntrinsic(self.rust_signature(cx))
524517
}
525518
}
526519

@@ -684,15 +677,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
684677
callsite: &'ll Value,
685678
llfn: &'ll Value,
686679
) {
687-
// if we are using the LLVM signature, use the LLVM attributes otherwise it might be problematic
688-
let name = llvm::get_value_name(llfn);
689-
if name.starts_with(b"llvm.")
690-
&& let Some(intrinsic) = llvm::Intrinsic::lookup(&name)
691-
{
692-
// FIXME: also do this for overloaded intrinsics
693-
if !intrinsic.is_overloaded() {
694-
return;
695-
}
680+
// Don't apply any attributes to LLVM intrinsics, they will be applied by AutoUpgrade
681+
if llvm::get_value_name(llfn).starts_with(b"llvm.") {
682+
return;
696683
}
697684

698685
let mut func_attrs = SmallVec::<[_; 2]>::new();

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@ use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
1818
use rustc_data_structures::fx::FxIndexSet;
1919
use rustc_middle::ty::{Instance, Ty};
2020
use rustc_sanitizers::{cfi, kcfi};
21+
use rustc_session::lint::builtin::{DEPRECATED_LLVM_INTRINSIC, UNKNOWN_LLVM_INTRINSIC};
2122
use rustc_target::callconv::FnAbi;
2223
use smallvec::SmallVec;
2324
use tracing::debug;
2425

2526
use crate::abi::{FnAbiLlvmExt, FunctionSignature};
26-
use crate::attributes;
2727
use crate::common::AsCCharPtr;
2828
use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx};
2929
use crate::llvm::AttributePlace::Function;
3030
use crate::llvm::{self, FromGeneric, Type, Value, Visibility};
31+
use crate::{attributes, errors};
3132

3233
/// Declare a function with a SimpleCx.
3334
///
@@ -148,52 +149,69 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
148149
) -> &'ll Value {
149150
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
150151

151-
let signature = fn_abi.llvm_type(self, name.as_bytes(), true);
152-
let llfn;
153-
154-
if let FunctionSignature::Intrinsic(fn_ty) = signature {
155-
// intrinsics have a specified set of attributes, so we don't use the `FnAbi` set for them
156-
llfn = declare_simple_fn(
157-
self,
158-
name,
159-
fn_abi.llvm_cconv(self),
160-
llvm::UnnamedAddr::Global,
161-
llvm::Visibility::Default,
162-
fn_ty,
163-
);
164-
} else {
165-
// Function addresses in Rust are never significant, allowing functions to
166-
// be merged.
167-
llfn = declare_raw_fn(
168-
self,
169-
name,
170-
fn_abi.llvm_cconv(self),
171-
llvm::UnnamedAddr::Global,
172-
llvm::Visibility::Default,
173-
signature.fn_ty(),
174-
);
152+
let signature = fn_abi.llvm_type(self, name.as_bytes());
153+
154+
let span = || instance.map(|instance| self.tcx.def_span(instance.def_id()));
155+
156+
if let FunctionSignature::LLVMSignature(_, llvm_fn_ty) = signature {
157+
// check if the intrinsic signatures match
158+
if !fn_abi.verify_intrinsic_signature(self, llvm_fn_ty) {
159+
self.tcx.dcx().emit_fatal(errors::IntrinsicSignatureMismatch {
160+
name,
161+
llvm_fn_ty: &format!("{llvm_fn_ty:?}"),
162+
rust_fn_ty: &format!("{:?}", fn_abi.rust_signature(self)),
163+
span: span(),
164+
});
165+
}
166+
}
167+
168+
// Function addresses in Rust are never significant, allowing functions to
169+
// be merged.
170+
let llfn = declare_raw_fn(
171+
self,
172+
name,
173+
fn_abi.llvm_cconv(self),
174+
llvm::UnnamedAddr::Global,
175+
llvm::Visibility::Default,
176+
signature.fn_ty(),
177+
);
178+
179+
if signature.intrinsic().is_none() {
180+
// Don't apply any attributes to intrinsics, they will be applied by AutoUpgrade
175181
fn_abi.apply_attrs_llfn(self, llfn, instance);
176182
}
177183

178-
if let FunctionSignature::MaybeInvalidIntrinsic(..) = signature {
184+
if let FunctionSignature::MaybeInvalid(..) = signature {
179185
let mut new_llfn = None;
180186
let can_upgrade =
181187
unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn, false) };
182188

183-
if can_upgrade {
184-
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
185-
if let Some(new_llfn) = new_llfn {
186-
self.tcx.dcx().note(format!(
187-
"Using deprecated intrinsic `{name}`, `{}` can be used instead",
188-
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
189-
));
189+
// we can emit diagnostics for local crates only
190+
if let Some(instance) = instance
191+
&& let Some(local_def_id) = instance.def_id().as_local()
192+
{
193+
let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
194+
let span = self.tcx.def_span(local_def_id);
195+
196+
if can_upgrade {
197+
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
198+
let msg = if let Some(new_llfn) = new_llfn {
199+
format!(
200+
"using deprecated intrinsic `{name}`, `{}` can be used instead",
201+
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
202+
)
203+
} else {
204+
format!("using deprecated intrinsic `{name}`")
205+
};
206+
self.tcx.node_lint(DEPRECATED_LLVM_INTRINSIC, hir_id, |d| {
207+
d.primary_message(msg).span(span);
208+
});
190209
} else {
191-
self.tcx.dcx().note(format!(
192-
"Using deprecated intrinsic `{name}`, consider using other intrinsics/instructions"
193-
));
210+
// This is either plain wrong, or this can be caused by incompatible LLVM versions, we let the user decide
211+
self.tcx.node_lint(UNKNOWN_LLVM_INTRINSIC, hir_id, |d| {
212+
d.primary_message(format!("invalid LLVM Intrinsic `{name}`")).span(span);
213+
});
194214
}
195-
} else {
196-
self.tcx.dcx().fatal(format!("Invalid LLVM intrinsic: `{name}`"))
197215
}
198216
}
199217

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,13 @@ pub(crate) struct FixedX18InvalidArch<'a> {
147147
#[derive(Diagnostic)]
148148
#[diag(codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0)]
149149
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
150+
151+
#[derive(Diagnostic)]
152+
#[diag(codegen_llvm_intrinsic_signature_mismatch)]
153+
pub(crate) struct IntrinsicSignatureMismatch<'a> {
154+
pub name: &'a str,
155+
pub llvm_fn_ty: &'a str,
156+
pub rust_fn_ty: &'a str,
157+
#[primary_span]
158+
pub span: Option<Span>,
159+
}

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ fn gen_fn<'a, 'll, 'tcx>(
10731073
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
10741074
) -> (&'ll Type, &'ll Value) {
10751075
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
1076-
let llty = fn_abi.llvm_type(cx, name.as_bytes(), true).fn_ty();
1076+
let llty = fn_abi.llvm_type(cx, name.as_bytes()).fn_ty();
10771077
let llfn = cx.declare_fn(name, fn_abi, None);
10781078
cx.set_frame_pointer_type(llfn);
10791079
cx.apply_target_cpu_attr(llfn);

compiler/rustc_codegen_llvm/src/type_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
309309
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
310310
fn_ptr: &'ll Value,
311311
) -> &'ll Type {
312-
fn_abi.llvm_type(self, &llvm::get_value_name(fn_ptr), false).fn_ty()
312+
fn_abi.llvm_type(self, &llvm::get_value_name(fn_ptr)).fn_ty()
313313
}
314314
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
315315
fn_abi.ptr_to_llvm_type(self)

0 commit comments

Comments
 (0)