Skip to content

Commit c464998

Browse files
committed
Refactor emitting errors to declare.rs, and use fluently-generated error messages
ss
1 parent 06ff86c commit c464998

12 files changed

+147
-100
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fa
33
44
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
55
6+
codegen_llvm_deprecated_intrinsic =
7+
Using deprecated intrinsic `{$name}`, consider using other intrinsics/instructions
8+
9+
codegen_llvm_deprecated_intrinsic_with_replacement =
10+
Using deprecated intrinsic `{$name}`, `{$replacement}` can be used instead
11+
612
codegen_llvm_dynamic_linking_with_lto =
713
cannot prefer dynamic linking when performing LTO
814
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
@@ -19,6 +25,12 @@ codegen_llvm_from_llvm_diag = {$message}
1925
2026
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
2127
28+
codegen_llvm_intrinsic_signature_mismatch =
29+
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
30+
31+
codegen_llvm_invalid_intrinsic =
32+
Invalid LLVM Intrinsic `{$name}`
33+
2234
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
2335
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
2436

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -302,20 +302,32 @@ impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
302302
}
303303

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

313316
impl<'ll> FunctionSignature<'ll> {
314317
pub(crate) fn fn_ty(&self) -> &'ll Type {
315318
match self {
316-
FunctionSignature::Intrinsic(fn_ty)
317-
| FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
318-
| FunctionSignature::Rust(fn_ty) => fn_ty,
319+
FunctionSignature::LLVMSignature(_, fn_ty)
320+
| FunctionSignature::RustSignature(_, fn_ty)
321+
| FunctionSignature::MaybeInvalid(fn_ty)
322+
| FunctionSignature::NotIntrinsic(fn_ty) => fn_ty,
323+
}
324+
}
325+
326+
pub(crate) fn intrinsic(&self) -> Option<llvm::Intrinsic> {
327+
match self {
328+
FunctionSignature::RustSignature(intrinsic, _)
329+
| FunctionSignature::LLVMSignature(intrinsic, _) => Some(*intrinsic),
330+
_ => None,
319331
}
320332
}
321333
}
@@ -326,12 +338,9 @@ pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
326338
/// When `do_verify` is set, this function performs checks for the signature of LLVM intrinsics
327339
/// and emits a fatal error if it doesn't match. These checks are important,but somewhat expensive
328340
/// So they are only used at function definitions, not at callsites
329-
fn llvm_type(
330-
&self,
331-
cx: &CodegenCx<'ll, 'tcx>,
332-
name: &[u8],
333-
do_verify: bool,
334-
) -> FunctionSignature<'ll>;
341+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll>;
342+
/// The normal Rust signature for this
343+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
335344
/// **If this function is an LLVM intrinsic** checks if the LLVM signature provided matches with this
336345
fn verify_intrinsic_signature(&self, cx: &CodegenCx<'ll, 'tcx>, llvm_ty: &'ll Type) -> bool;
337346
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
@@ -499,58 +508,41 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
499508
return false;
500509
}
501510

502-
// todo: add bypasses for types not accessible from Rust here
503511
iter::once((rust_return_ty, llvm_return_ty))
504512
.chain(iter::zip(rust_argument_tys, llvm_argument_tys))
505513
.all(|(rust_ty, llvm_ty)| cx.equate_ty(rust_ty, llvm_ty))
506514
}
507515

508-
fn llvm_type(
509-
&self,
510-
cx: &CodegenCx<'ll, 'tcx>,
511-
name: &[u8],
512-
do_verify: bool,
513-
) -> FunctionSignature<'ll> {
514-
let mut maybe_invalid = false;
516+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
517+
let return_ty = self.llvm_return_type(cx);
518+
let argument_tys = self.llvm_argument_types(cx);
519+
520+
if self.c_variadic {
521+
cx.type_variadic_func(&argument_tys, return_ty)
522+
} else {
523+
cx.type_func(&argument_tys, return_ty)
524+
}
525+
}
515526

527+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll> {
516528
if name.starts_with(b"llvm.") {
517529
if let Some(intrinsic) = llvm::Intrinsic::lookup(name) {
518530
if !intrinsic.is_overloaded() {
519531
// FIXME: also do this for overloaded intrinsics
520-
let llvm_fn_ty = cx.intrinsic_type(intrinsic, &[]);
521-
if do_verify {
522-
if !self.verify_intrinsic_signature(cx, llvm_fn_ty) {
523-
cx.tcx.dcx().fatal(format!(
524-
"Intrinsic signature mismatch for `{}`: expected signature `{llvm_fn_ty:?}`",
525-
str::from_utf8(name).unwrap()
526-
));
527-
}
528-
}
529-
return FunctionSignature::Intrinsic(llvm_fn_ty);
532+
FunctionSignature::LLVMSignature(intrinsic, cx.intrinsic_type(intrinsic, &[]))
533+
} else {
534+
FunctionSignature::RustSignature(intrinsic, self.rust_signature(cx))
530535
}
531536
} else {
532537
// it's one of 2 cases,
533538
// - either the base name is invalid
534539
// - it has been superceded by something else, so the intrinsic was removed entirely
535540
// to check for upgrades, we need the `llfn`, so we defer it for now
536541

537-
maybe_invalid = true;
542+
FunctionSignature::MaybeInvalid(self.rust_signature(cx))
538543
}
539-
}
540-
541-
let return_ty = self.llvm_return_type(cx);
542-
let argument_tys = self.llvm_argument_types(cx);
543-
544-
let fn_ty = if self.c_variadic {
545-
cx.type_variadic_func(&argument_tys, return_ty)
546544
} else {
547-
cx.type_func(&argument_tys, return_ty)
548-
};
549-
550-
if maybe_invalid {
551-
FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
552-
} else {
553-
FunctionSignature::Rust(fn_ty)
545+
FunctionSignature::NotIntrinsic(self.rust_signature(cx))
554546
}
555547
}
556548

@@ -699,15 +691,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
699691
callsite: &'ll Value,
700692
llfn: &'ll Value,
701693
) {
702-
// if we are using the LLVM signature, use the LLVM attributes otherwise it might be problematic
703-
let name = llvm::get_value_name(llfn);
704-
if name.starts_with(b"llvm.")
705-
&& let Some(intrinsic) = llvm::Intrinsic::lookup(name)
706-
{
707-
// FIXME: also do this for overloaded intrinsics
708-
if !intrinsic.is_overloaded() {
709-
return;
710-
}
694+
// Don't apply any attributes to LLVM intrinsics, they will be applied by AutoUpgrade
695+
if llvm::get_value_name(llfn).starts_with(b"llvm.") {
696+
return;
711697
}
712698

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

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::llvm::AttributePlace::Function;
2929
use crate::llvm::Visibility;
3030
use crate::type_::Type;
3131
use crate::value::Value;
32-
use crate::{attributes, llvm};
32+
use crate::{attributes, errors, llvm};
3333

3434
/// Declare a function with a SimpleCx.
3535
///
@@ -150,52 +150,59 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
150150
) -> &'ll Value {
151151
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
152152

153-
let signature = fn_abi.llvm_type(self, name.as_bytes(), true);
154-
let llfn;
153+
let signature = fn_abi.llvm_type(self, name.as_bytes());
155154

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

180-
if let FunctionSignature::MaybeInvalidIntrinsic(..) = signature {
185+
if let FunctionSignature::MaybeInvalid(..) = signature {
181186
let mut new_llfn = None;
182187
let can_upgrade =
183188
unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn, false) };
184189

185190
if can_upgrade {
186191
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
187192
if let Some(new_llfn) = new_llfn {
188-
self.tcx.dcx().note(format!(
189-
"Using deprecated intrinsic `{name}`, `{}` can be used instead",
190-
str::from_utf8(llvm::get_value_name(new_llfn)).unwrap()
191-
));
193+
self.tcx.dcx().emit_note(errors::DeprecatedIntrinsicWithReplacement {
194+
name,
195+
replacement: str::from_utf8(llvm::get_value_name(new_llfn)).unwrap(),
196+
span: span(),
197+
});
192198
} else if self.tcx.sess.opts.verbose {
193-
self.tcx.dcx().note(format!(
194-
"Using deprecated intrinsic `{name}`, consider using other intrinsics/instructions"
195-
));
199+
// At least for now, we are only emitting notes for deprecated intrinsics with no direct replacement
200+
// because they are used quite a lot in stdarch. After the stdarch uses has been removed, we can make
201+
// this always emit a note (or even an warning)
202+
self.tcx.dcx().emit_note(errors::DeprecatedIntrinsic { name, span: span() });
196203
}
197204
} else {
198-
self.tcx.dcx().fatal(format!("Invalid LLVM intrinsic: `{name}`"))
205+
self.tcx.dcx().emit_fatal(errors::InvalidIntrinsic { name, span: span() });
199206
}
200207
}
201208

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,38 @@ pub(crate) struct FixedX18InvalidArch<'a> {
209209
#[derive(Diagnostic)]
210210
#[diag(codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0)]
211211
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
212+
213+
#[derive(Diagnostic)]
214+
#[diag(codegen_llvm_intrinsic_signature_mismatch)]
215+
pub(crate) struct IntrinsicSignatureMismatch<'a> {
216+
pub name: &'a str,
217+
pub llvm_fn_ty: &'a str,
218+
pub rust_fn_ty: &'a str,
219+
#[primary_span]
220+
pub span: Option<Span>,
221+
}
222+
223+
#[derive(Diagnostic)]
224+
#[diag(codegen_llvm_invalid_intrinsic)]
225+
pub(crate) struct InvalidIntrinsic<'a> {
226+
pub name: &'a str,
227+
#[primary_span]
228+
pub span: Option<Span>,
229+
}
230+
231+
#[derive(Diagnostic)]
232+
#[diag(codegen_llvm_deprecated_intrinsic)]
233+
pub(crate) struct DeprecatedIntrinsic<'a> {
234+
pub name: &'a str,
235+
#[primary_span]
236+
pub span: Option<Span>,
237+
}
238+
239+
#[derive(Diagnostic)]
240+
#[diag(codegen_llvm_deprecated_intrinsic_with_replacement)]
241+
pub(crate) struct DeprecatedIntrinsicWithReplacement<'a> {
242+
pub name: &'a str,
243+
pub replacement: &'a str,
244+
#[primary_span]
245+
pub span: Option<Span>,
246+
}

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ fn gen_fn<'a, 'll, 'tcx>(
10671067
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
10681068
) -> (&'ll Type, &'ll Value) {
10691069
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
1070-
let llty = fn_abi.llvm_type(cx, name.as_bytes(), true).fn_ty();
1070+
let llty = fn_abi.llvm_type(cx, name.as_bytes()).fn_ty();
10711071
let llfn = cx.declare_fn(name, fn_abi, None);
10721072
cx.set_frame_pointer_type(llfn);
10731073
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
@@ -307,7 +307,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
307307
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
308308
fn_ptr: &'ll Value,
309309
) -> &'ll Type {
310-
fn_abi.llvm_type(self, llvm::get_value_name(fn_ptr), false).fn_ty()
310+
fn_abi.llvm_type(self, llvm::get_value_name(fn_ptr)).fn_ty()
311311
}
312312
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
313313
fn_abi.ptr_to_llvm_type(self)

tests/ui/codegen/deprecated-llvm-intrinsic.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ pub struct i8x8([i8; 8]);
1818
extern "unadjusted" {
1919
#[link_name = "llvm.aarch64.neon.rbit.v8i8"]
2020
fn foo(a: i8x8) -> i8x8;
21+
//~^ NOTE: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
2122
}
2223

2324
#[target_feature(enable = "neon")]
2425
pub unsafe fn bar(a: i8x8) -> i8x8 {
2526
foo(a)
2627
}
27-
28-
//~? NOTE: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
note: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
2+
--> $DIR/deprecated-llvm-intrinsic.rs:20:5
3+
|
4+
LL | fn foo(a: i8x8) -> i8x8;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
26

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
//@ build-fail
22

33
#![feature(link_llvm_intrinsics, abi_unadjusted)]
4-
#![allow(internal_features, non_camel_case_types, improper_ctypes)]
54

65
extern "unadjusted" {
76
#[link_name = "llvm.assume"]
87
fn foo();
8+
//~^ ERROR: Intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
99
}
1010

1111
pub fn main() {
1212
unsafe { foo() }
1313
}
14-
15-
//~? ERROR: Intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
error: Intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`
1+
error: Intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
2+
--> $DIR/incorrect-llvm-intrinsic-signature.rs:7:5
3+
|
4+
LL | fn foo();
5+
| ^^^^^^^^^
26

37
error: aborting due to 1 previous error
48

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
//@ build-fail
22

33
#![feature(link_llvm_intrinsics, abi_unadjusted)]
4-
#![allow(internal_features, non_camel_case_types, improper_ctypes)]
54

65
extern "unadjusted" {
76
#[link_name = "llvm.abcde"]
87
fn foo();
8+
//~^ ERROR: Invalid LLVM Intrinsic `llvm.abcde`
99
}
1010

1111
pub fn main() {
1212
unsafe { foo() }
1313
}
14-
15-
//~? ERROR: Invalid LLVM intrinsic: `llvm.abcde`

0 commit comments

Comments
 (0)