Skip to content

Commit 666f92e

Browse files
committed
Create lints for deprecated and invalid intrinsics
1 parent afa7252 commit 666f92e

File tree

9 files changed

+124
-56
lines changed

9 files changed

+124
-56
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@ codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z au
22
33
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
44
5-
codegen_llvm_deprecated_intrinsic =
6-
Using deprecated intrinsic `{$name}`, consider using other intrinsics/instructions
7-
8-
codegen_llvm_deprecated_intrinsic_with_replacement =
9-
Using deprecated intrinsic `{$name}`, `{$replacement}` can be used instead
10-
115
126
137
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
@@ -22,9 +16,6 @@ codegen_llvm_intrinsic_signature_mismatch =
2216
codegen_llvm_intrinsic_wrong_arch =
2317
Intrinsic `{$name}` cannot be used with target arch `{$target_arch}`
2418
25-
codegen_llvm_invalid_intrinsic =
26-
Invalid LLVM Intrinsic `{$name}`
27-
2819
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
2920
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
3021

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
375375
return true;
376376
}
377377

378-
// Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
379-
// due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
378+
// Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
379+
// due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
380380
// as, well, packed structs, so they won't match with those either)
381381
if self.type_kind(llvm_ty) == TypeKind::Struct
382382
&& self.type_kind(rust_ty) == TypeKind::Struct

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ 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;
@@ -216,22 +217,32 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
216217
let can_upgrade =
217218
unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn, false) };
218219

219-
if can_upgrade {
220-
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
221-
if let Some(new_llfn) = new_llfn {
222-
self.tcx.dcx().emit_note(errors::DeprecatedIntrinsicWithReplacement {
223-
name,
224-
replacement: str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap(),
225-
span: span(),
220+
// we can emit diagnostics for local crates only
221+
if let Some(instance) = instance
222+
&& let Some(local_def_id) = instance.def_id().as_local()
223+
{
224+
let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
225+
let span = self.tcx.def_span(local_def_id);
226+
227+
if can_upgrade {
228+
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
229+
let msg = if let Some(new_llfn) = new_llfn {
230+
format!(
231+
"Using deprecated intrinsic `{name}`, `{}` can be used instead",
232+
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
233+
)
234+
} else {
235+
format!("Using deprecated intrinsic `{name}`")
236+
};
237+
self.tcx.node_lint(DEPRECATED_LLVM_INTRINSIC, hir_id, |d| {
238+
d.primary_message(msg).span(span);
239+
});
240+
} else {
241+
// This is either plain wrong, or this can be caused by incompatible LLVM versions, we let the user decide
242+
self.tcx.node_lint(UNKNOWN_LLVM_INTRINSIC, hir_id, |d| {
243+
d.primary_message(format!("Invalid LLVM Intrinsic `{name}`")).span(span);
226244
});
227-
} else if self.tcx.sess.opts.verbose {
228-
// At least for now, we are only emitting notes for deprecated intrinsics with no direct replacement
229-
// because they are used quite a lot in stdarch. After the stdarch uses has been removed, we can make
230-
// this always emit a note (or even an warning)
231-
self.tcx.dcx().emit_note(errors::DeprecatedIntrinsic { name, span: span() });
232245
}
233-
} else {
234-
self.tcx.dcx().emit_fatal(errors::InvalidIntrinsic { name, span: span() });
235246
}
236247
}
237248

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -158,31 +158,6 @@ pub(crate) struct IntrinsicSignatureMismatch<'a> {
158158
pub span: Option<Span>,
159159
}
160160

161-
#[derive(Diagnostic)]
162-
#[diag(codegen_llvm_invalid_intrinsic)]
163-
pub(crate) struct InvalidIntrinsic<'a> {
164-
pub name: &'a str,
165-
#[primary_span]
166-
pub span: Option<Span>,
167-
}
168-
169-
#[derive(Diagnostic)]
170-
#[diag(codegen_llvm_deprecated_intrinsic)]
171-
pub(crate) struct DeprecatedIntrinsic<'a> {
172-
pub name: &'a str,
173-
#[primary_span]
174-
pub span: Option<Span>,
175-
}
176-
177-
#[derive(Diagnostic)]
178-
#[diag(codegen_llvm_deprecated_intrinsic_with_replacement)]
179-
pub(crate) struct DeprecatedIntrinsicWithReplacement<'a> {
180-
pub name: &'a str,
181-
pub replacement: &'a str,
182-
#[primary_span]
183-
pub span: Option<Span>,
184-
}
185-
186161
#[derive(Diagnostic)]
187162
#[diag(codegen_llvm_intrinsic_wrong_arch)]
188163
pub(crate) struct IntrinsicWrongArch<'a> {

compiler/rustc_codegen_llvm/src/type_.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
7171
}
7272

7373
pub(crate) fn get_return_type(&self, ty: &'ll Type) -> &'ll Type {
74-
unsafe {
75-
llvm::LLVMGetReturnType(ty)
76-
}
74+
unsafe { llvm::LLVMGetReturnType(ty) }
7775
}
7876

7977
pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ declare_lint_pass! {
3535
DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
3636
DEPRECATED,
3737
DEPRECATED_IN_FUTURE,
38+
DEPRECATED_LLVM_INTRINSIC,
3839
DEPRECATED_SAFE_2024,
3940
DEPRECATED_WHERE_CLAUSE_LOCATION,
4041
DUPLICATE_MACRO_ATTRIBUTES,
@@ -117,6 +118,7 @@ declare_lint_pass! {
117118
UNKNOWN_CRATE_TYPES,
118119
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
119120
UNKNOWN_LINTS,
121+
UNKNOWN_LLVM_INTRINSIC,
120122
UNNAMEABLE_TEST_ITEMS,
121123
UNNAMEABLE_TYPES,
122124
UNREACHABLE_CODE,
@@ -5138,3 +5140,83 @@ declare_lint! {
51385140
"detects tail calls of functions marked with `#[track_caller]`",
51395141
@feature_gate = explicit_tail_calls;
51405142
}
5143+
5144+
declare_lint! {
5145+
/// The `unknown_llvm_intrinsic` lint detects usage of unknown LLVM intrinsics.
5146+
///
5147+
/// ### Example
5148+
///
5149+
/// ```rust,compile_fail
5150+
/// #![feature(link_llvm_intrinsics, abi_unadjusted)]
5151+
///
5152+
/// unsafe extern "unadjusted" {
5153+
/// #[link_name = "llvm.abcde"]
5154+
/// fn foo();
5155+
/// }
5156+
///
5157+
/// # #[inline(never)]
5158+
/// pub fn bar() {
5159+
/// unsafe { foo() }
5160+
/// }
5161+
/// #
5162+
/// # fn main() {
5163+
/// # bar();
5164+
/// # }
5165+
/// ```
5166+
///
5167+
/// {{produces}}
5168+
///
5169+
/// ### Explanation
5170+
///
5171+
/// Linking to an unknown LLVM intrinsic may cause linker errors (in general it's UB),
5172+
/// so this lint captures those undesirable scenarios.
5173+
pub UNKNOWN_LLVM_INTRINSIC,
5174+
Deny,
5175+
"detects uses of unknown LLVM intrinsics",
5176+
@feature_gate = link_llvm_intrinsics;
5177+
}
5178+
5179+
declare_lint! {
5180+
/// The `deprecated_llvm_intrinsic` lint detects usage of deprecated LLVM intrinsics.
5181+
///
5182+
/// ### Example
5183+
///
5184+
/// ```rust,ignore (fails on non-x86)
5185+
/// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
5186+
/// #![feature(link_llvm_intrinsics, abi_unadjusted)]
5187+
/// #![deny(deprecated_llvm_intrinsic)]
5188+
///
5189+
/// unsafe extern "unadjusted" {
5190+
/// #[link_name = "llvm.x86.addcarryx.u32"]
5191+
/// fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
5192+
/// }
5193+
///
5194+
/// #[inline(never)]
5195+
/// #[target_feature(enable = "adx")]
5196+
/// pub fn bar(a: u8, b: u32, c: u32, d: &mut u32) -> u8 {
5197+
/// unsafe { foo(a, b, c, d) }
5198+
/// }
5199+
/// ```
5200+
///
5201+
/// This will produce:
5202+
///
5203+
/// ```text
5204+
/// error: Using deprecated intrinsic `llvm.x86.addcarryx.u32`
5205+
/// --> example.rs:7:5
5206+
/// |
5207+
/// 7 | fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
5208+
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5209+
/// |
5210+
/// ```
5211+
///
5212+
/// ### Explanation
5213+
///
5214+
/// LLVM periodically updates its list of intrinsics. Removed intrinsics are unlikely
5215+
/// to be removed, but they may optimize less well than their new versions, so it's
5216+
/// best to use the new version. Also, some deprecated intrinsics might have buggy
5217+
/// behavior
5218+
pub DEPRECATED_LLVM_INTRINSIC,
5219+
Allow,
5220+
"detects uses of deprecated LLVM intrinsics",
5221+
@feature_gate = link_llvm_intrinsics;
5222+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ use minicore::*;
1616
pub struct i8x8([i8; 8]);
1717

1818
extern "unadjusted" {
19+
#![warn(deprecated_llvm_intrinsic)]
1920
#[link_name = "llvm.aarch64.neon.rbit.v8i8"]
2021
fn foo(a: i8x8) -> i8x8;
21-
//~^ NOTE: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
22+
//~^ WARN: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
2223
}
2324

2425
#[target_feature(enable = "neon")]
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
note: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
2-
--> $DIR/deprecated-llvm-intrinsic.rs:20:5
1+
warning: Using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
2+
--> $DIR/deprecated-llvm-intrinsic.rs:21:5
33
|
44
LL | fn foo(a: i8x8) -> i8x8;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/deprecated-llvm-intrinsic.rs:19:13
9+
|
10+
LL | #![warn(deprecated_llvm_intrinsic)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
warning: 1 warning emitted
614

tests/ui/codegen/invalid-llvm-intrinsic.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error: Invalid LLVM Intrinsic `llvm.abcde`
33
|
44
LL | fn foo();
55
| ^^^^^^^^^
6+
|
7+
= note: `#[deny(unknown_llvm_intrinsic)]` on by default
68

79
error: aborting due to 1 previous error
810

0 commit comments

Comments
 (0)