Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
203c216
Cc PR author + assignee when opening the FCP thread on Zulip
ada4a Apr 5, 2026
14e481d
Handle different root comparison contexts in `SpanlessEq`
Jarcho Sep 29, 2025
436aad4
Add a check for some followed by filter
Apr 7, 2026
0a73f89
Merge commit '377417cf68ab671a67af222a551623ce228ce540' into clippy-s…
flip1995 Apr 30, 2026
69f7046
Eliminate `rustc_lint_defs`' dependency on `rustc_ast`.
nnethercote Apr 13, 2026
0c4849e
Add extra symbol check for `.to_owned()`
EvoPot May 2, 2026
efe239a
Rollup merge of #156074 - EvoPot:cow-diag-item, r=chenyukang
JonathanBrouwer May 2, 2026
03a2acd
Handle different root contexts in `SpanlessEq` (#15793)
dswij May 2, 2026
d08d4e7
miri: remove retag statements, make typed copies retag implicitly ins…
RalfJung Mar 24, 2026
00cb5cb
Remove more spans from AttributeKind
mejrs May 1, 2026
a2766a5
Auto merge of #154341 - RalfJung:retag-on-typed-copy, r=oli-obk
bors May 2, 2026
77f1fca
Rollup merge of #156065 - mejrs:spanculler, r=JonathanBrouwer
jhpratt May 3, 2026
fa25734
No longer in vacation
samueltardieu May 3, 2026
797f038
No longer in vacation (#16955)
samueltardieu May 3, 2026
3e0e895
Rip out rustc_layout_scalar_valid_range_* attribute support
oli-obk Feb 13, 2026
e1e72db
Auto merge of #155996 - flip1995:clippy-subtree-update, r=Manishearth
bors May 3, 2026
7db6bf7
fix: [needless_return_with_question_mark] trigger in async functions
Gri-ffin May 1, 2026
9d3192a
Rollup merge of #155433 - oli-obk:bye-bye-long-attribute, r=RalfJung,…
JonathanBrouwer May 3, 2026
73f2ae7
fix: [needless_return_with_question_mark] trigger in async functions …
samueltardieu May 3, 2026
6310134
Add a check for some followed by filter (#15745)
ada4a May 4, 2026
21487c1
Update `askama` version to `0.16.0` in `clippy`
GuillaumeGomez May 4, 2026
7a5e25a
New lint: `manual_clear`
samueltardieu Feb 22, 2026
6cfda5c
Rollup merge of #156127 - GuillaumeGomez:update-askama, r=Urgau
JonathanBrouwer May 5, 2026
9c8be59
fix: `manual_option_zip` FP when the outer param is used in closure
profetia May 5, 2026
ce93eb0
test: Prepare tests for new Cargo build-dir layout
ranger-ross May 5, 2026
98098df
test: Prepare tests for new Cargo build-dir layout (#16966)
samueltardieu May 6, 2026
ebc9120
support `ast::ExprKind::Move` in clippy
TaKO8Ki Apr 9, 2026
0d1e095
fix: self deref detecting in check_clone_on_copy.
Kokoro2336 May 1, 2026
840a6fa
fix: incompatibility of `non_canonical_clone_impl` and `implicit_retu…
samueltardieu May 7, 2026
f197201
New lint: `manual_clear` (#16617)
flip1995 May 7, 2026
bf7047d
Cc PR author + assignee when opening the FCP thread on Zulip (#16814)
flip1995 May 7, 2026
6bc532f
Reborrow traits
aapoalas Feb 26, 2026
f858a83
remove dswij from rotation
dswij May 8, 2026
2e6b82d
remove dswij from rotation (#16975)
dswij May 8, 2026
f763854
Fix `manual_option_zip` FP when the outer param is used in closure (#…
samueltardieu May 8, 2026
bd93ed5
Add function to extract the symbol name from the attributes
Urgau Apr 19, 2026
32ab700
Add weak-only lang items for core runtime symbols
Urgau Apr 19, 2026
c15eded
Add lint against invalid runtime symbol definitions
Urgau Apr 12, 2026
6f899df
Handle static whose type is a function pointer
Urgau Apr 19, 2026
05165c1
Fix invalid `memcpy` definition in codegen test and UI tests
Urgau Apr 19, 2026
87d0090
Fix invalid definition of `strlen` in error codes documentation
Urgau Apr 19, 2026
9413ccd
Fix typos in book
samueltardieu May 11, 2026
a453e8c
Add inline_trait_bounds lint
moses7054 May 11, 2026
95e1ea8
Rollup merge of #155023 - TaKO8Ki:move-expr-1, r=nikomatsakis
JonathanBrouwer May 11, 2026
c4b8c6d
Add new lint `inline_trait_bounds` (#16486)
samueltardieu May 12, 2026
d3a82bf
Fix typos in book (#16993)
flip1995 May 12, 2026
4d9634c
Update dependencies to remove windows-targets dependency
bjorn3 May 12, 2026
2b41e36
Update dependencies to remove windows-targets dependency (#17000)
Jarcho May 12, 2026
2493ef1
rustdoc: `SpanMapVisitor`: Cache `TypeckResults`
fmease May 10, 2026
b0eb4ff
Don't check if the resolution of `TypeRelative` paths is `Err` becaus…
fmease May 10, 2026
f5ad60c
Inline non-self-descriptive fn `infer_id`
fmease May 10, 2026
bfcaf51
Don't create a path with zero segments
fmease May 10, 2026
efaf441
Don't special-case `ExprKind::Call`
fmease May 10, 2026
e205784
Don't try to resolve type-dependent paths in anon consts
fmease May 13, 2026
2c30279
Add `send_process_group_signal` to existing `unix_send_signal` feature
jmillikin May 13, 2026
6e99c68
use `deref_patterns` in `rustdoc`
cyrgani May 13, 2026
7bf5fe7
Add `ChildExt::kill_process_group`
jmillikin May 13, 2026
3d0ee52
Privacy: move macros handling to early stage
Bryanskiy May 8, 2026
d0611d8
Merge remote-tracking branch 'upstream/master' into rustup
flip1995 May 13, 2026
0f05543
Bump nightly version -> 2026-05-13
flip1995 May 13, 2026
b147b68
Rustup (#17009)
flip1995 May 13, 2026
30e15b5
Merge commit 'b147b68c9bbc5ad44aea4220e6f68fd281f19c64' into clippy-s…
flip1995 May 13, 2026
4e3fe3e
Update Cargo.lock
flip1995 May 13, 2026
5df3bf4
Rollup merge of #156552 - flip1995:clippy-subtree-update, r=Manishearth
JonathanBrouwer May 13, 2026
503a94e
Rollup merge of #155521 - Urgau:runtime-symbols, r=davidtwco
JonathanBrouwer May 13, 2026
961e2fb
Rollup merge of #156500 - Bryanskiy:macros_vis, r=petrochenkov
JonathanBrouwer May 13, 2026
f561b59
Rollup merge of #156413 - fmease:rustdoc-ltd-improvs, r=GuillaumeGomez
JonathanBrouwer May 13, 2026
1120101
Rollup merge of #156539 - jmillikin:unix-childext-killpg, r=nia-e
JonathanBrouwer May 13, 2026
bf60b47
Rollup merge of #156540 - cyrgani:unbox-rustdoc, r=GuillaumeGomez
JonathanBrouwer May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4267,6 +4267,7 @@ dependencies = [
"rustc_parse_format",
"rustc_session",
"rustc_span",
"rustc_symbol_mangling",
"rustc_target",
"rustc_trait_selection",
"smallvec",
Expand Down Expand Up @@ -5948,9 +5949,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"

[[package]]
name = "ui_test"
version = "0.30.4"
version = "0.30.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ada249620d81f010b9a1472b63a5077ac7c722dd0f4bacf6528b313d0b8c15d8"
checksum = "980133b75aa9a95dc94feaf629d92d22c1172186f1fa1266b91f5b91414cf9a5"
dependencies = [
"annotate-snippets 0.11.5",
"anyhow",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0755.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ side effects or infinite loops:

extern "C" {
#[unsafe(ffi_pure)] // ok!
pub fn strlen(s: *const i8) -> isize;
pub fn strlen(s: *const std::ffi::c_char) -> usize;
}
# fn main() {}
```
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0756.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ which have no side effects except for their return value:

extern "C" {
#[unsafe(ffi_const)] // ok!
pub fn strlen(s: *const i8) -> i32;
pub fn strlen(s: *const std::ffi::c_char) -> usize;
}
# fn main() {}
```
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ language_item_table! {

// Used to fallback `{float}` to `f32` when `f32: From<{float}>`
From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1);

// Runtime symbols
MemCpy, sym::memcpy_fn, memcpy_fn, Target::Fn, GenericRequirement::None;
MemMove, sym::memmove_fn, memmove_fn, Target::Fn, GenericRequirement::None;
MemSet, sym::memset_fn, memset_fn, Target::Fn, GenericRequirement::None;
MemCmp, sym::memcmp_fn, memcmp_fn, Target::Fn, GenericRequirement::None;
Bcmp, sym::bcmp_fn, bcmp_fn, Target::Fn, GenericRequirement::None;
StrLen, sym::strlen_fn, strlen_fn, Target::Fn, GenericRequirement::None;
}

/// The requirement imposed on the generics of a lang item
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_hir/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,29 @@ macro_rules! weak_lang_items {
}
}

macro_rules! weak_only_lang_items {
($($item:ident,)*) => {
pub static WEAK_ONLY_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*];

impl LangItem {
pub fn is_weak_only(self) -> bool {
matches!(self, $(LangItem::$item)|*)
}
}
}
}

weak_lang_items! {
PanicImpl, rust_begin_unwind;
EhPersonality, rust_eh_personality;
EhCatchTypeinfo, rust_eh_catch_typeinfo;
}

weak_only_lang_items! {
MemCpy,
MemMove,
MemSet,
MemCmp,
Bcmp,
StrLen,
}
1 change: 1 addition & 0 deletions compiler/rustc_lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ rustc_middle = { path = "../rustc_middle" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ mod precedence;
mod ptr_nulls;
mod redundant_semicolon;
mod reference_casting;
mod runtime_symbols;
mod shadowed_into_iter;
mod static_mut_refs;
mod traits;
Expand Down Expand Up @@ -113,6 +114,7 @@ use precedence::*;
use ptr_nulls::*;
use redundant_semicolon::*;
use reference_casting::*;
use runtime_symbols::*;
use rustc_hir::def_id::LocalModDefId;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
Expand Down Expand Up @@ -242,6 +244,7 @@ late_lint_methods!(
AsyncFnInTrait: AsyncFnInTrait,
NonLocalDefinitions: NonLocalDefinitions::default(),
InteriorMutableConsts: InteriorMutableConsts,
RuntimeSymbols: RuntimeSymbols,
ImplTraitOvercaptures: ImplTraitOvercaptures,
IfLetRescope: IfLetRescope::default(),
StaticMutRefs: StaticMutRefs,
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,33 @@ pub(crate) enum UseLetUnderscoreIgnoreSuggestion {
},
}

// runtime_symbols.rs
#[derive(Diagnostic)]
pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> {
#[diag(
"invalid definition of the runtime `{$symbol_name}` symbol used by the standard library"
)]
#[note(
"expected `{$expected_fn_sig}`
found `{$found_fn_sig}`"
)]
#[help(
"either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`"
)]
FnDef { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> },
#[diag(
"invalid definition of the runtime `{$symbol_name}` symbol used by the standard library"
)]
#[note(
"expected `{$expected_fn_sig}`
found `static {$symbol_name}: {$static_ty}`"
)]
#[help(
"either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = \"{$symbol_name}\")]`"
)]
Static { symbol_name: String, static_ty: Ty<'tcx>, expected_fn_sig: Ty<'tcx> },
}

// drop_forget_useless.rs
#[derive(Diagnostic)]
#[diag("calls to `std::mem::drop` with a reference instead of an owned value does nothing")]
Expand Down
205 changes: 205 additions & 0 deletions compiler/rustc_lint/src/runtime_symbols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, FnSig, ForeignItemKind, LanguageItems};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::Span;
use rustc_trait_selection::infer::TyCtxtInferExt;

use crate::lints::RedefiningRuntimeSymbolsDiag;
use crate::{LateContext, LateLintPass, LintContext};

declare_lint! {
/// The `invalid_runtime_symbol_definitions` lint checks the signature of items whose
/// symbol name is a runtime symbols expected by `core`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #[unsafe(no_mangle)]
/// pub fn strlen() {} // invalid definition of the `strlen` function
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Up-most care is required when defining runtime symbols assumed and
/// used by the standard library. They must follow the C specification, not use any
/// standard-library facility or undefined behavior may occur.
///
/// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`,
/// `bcmp` and `strlen`.
///
/// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library
pub INVALID_RUNTIME_SYMBOL_DEFINITIONS,
Deny,
"invalid definition of a symbol used by the standard library"
}

declare_lint_pass!(RuntimeSymbols => [INVALID_RUNTIME_SYMBOL_DEFINITIONS]);

static EXPECTED_SYMBOLS: &[ExpectedSymbol] = &[
ExpectedSymbol { symbol: "memcpy", lang: LanguageItems::memcpy_fn },
ExpectedSymbol { symbol: "memmove", lang: LanguageItems::memmove_fn },
ExpectedSymbol { symbol: "memset", lang: LanguageItems::memset_fn },
ExpectedSymbol { symbol: "memcmp", lang: LanguageItems::memcmp_fn },
ExpectedSymbol { symbol: "bcmp", lang: LanguageItems::bcmp_fn },
ExpectedSymbol { symbol: "strlen", lang: LanguageItems::strlen_fn },
];

#[derive(Copy, Clone, Debug)]
struct ExpectedSymbol {
symbol: &'static str,
lang: fn(&LanguageItems) -> Option<DefId>,
}

impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
// Bail-out if the item is not a function/method or static.
match item.kind {
hir::ItemKind::Fn { sig, ident: _, generics, body: _, has_body: _ } => {
// Generic functions cannot have the same runtime symbol as we do not allow
// any symbol attributes.
if !generics.params.is_empty() {
return;
}

// Try to get the overridden symbol name of this function (our mangling
// cannot ever conflict with runtime symbols, so no need to check for those).
let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs(
cx.tcx,
rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()),
) else {
return;
};

check_fn(cx, &symbol_name, sig, item.owner_id.def_id);
}
hir::ItemKind::Static(..) => {
// Compute the symbol name of this static (without mangling, as our mangling
// cannot ever conflict with runtime symbols).
let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs(
cx.tcx,
rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()),
) else {
return;
};

let def_id = item.owner_id.def_id;

check_static(cx, &symbol_name, def_id, item.span);
}
hir::ItemKind::ForeignMod { abi: _, items } => {
for item in items {
let item = cx.tcx.hir_foreign_item(*item);

let did = item.owner_id.def_id;
let instance = Instance::new_raw(
did.to_def_id(),
ty::List::identity_for_item(cx.tcx, did),
);
let symbol_name = cx.tcx.symbol_name(instance);

match item.kind {
ForeignItemKind::Fn(fn_sig, _idents, _generics) => {
check_fn(cx, &symbol_name.name, fn_sig, did);
}
ForeignItemKind::Static(..) => {
check_static(cx, &symbol_name.name, did, item.span);
}
ForeignItemKind::Type => return,
}
}
}
_ => return,
}
}
}

fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalDefId) {
let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else {
// The symbol name does not correspond to a runtime symbols, bail out
return;
};

let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else {
// Can't find the corresponding language item, bail out
return;
};

// Get the two function signatures
let lang_sig = cx.tcx.normalize_erasing_regions(
cx.typing_env(),
cx.tcx.fn_sig(expected_def_id).instantiate_identity(),
);
let user_sig = cx
.tcx
.normalize_erasing_regions(cx.typing_env(), cx.tcx.fn_sig(did).instantiate_identity());

// Compare the two signatures with an inference context
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
let cause = rustc_middle::traits::ObligationCause::misc(sig.span, did);
let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig);

// If they don't match, emit our own mismatch signatures
if let Err(_terr) = result {
// Create fn pointers for diagnostics purpose
let expected = Ty::new_fn_ptr(cx.tcx, lang_sig);
let actual = Ty::new_fn_ptr(cx.tcx, user_sig);

cx.emit_span_lint(
INVALID_RUNTIME_SYMBOL_DEFINITIONS,
sig.span,
RedefiningRuntimeSymbolsDiag::FnDef {
symbol_name: symbol_name.to_string(),
found_fn_sig: actual,
expected_fn_sig: expected,
},
);
}
}

fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId, sp: Span) {
let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else {
// The symbol name does not correspond to a runtime symbols, bail out
return;
};

let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else {
// Can't find the corresponding language item, bail out
return;
};

// Get the static type
let static_ty = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip();

// Peel Option<...> and get the inner type (see std weak! macro with #[linkage = "extern_weak"])
let inner_static_ty: Ty<'_> = match static_ty.kind() {
ty::Adt(def, args) if Some(def.did()) == cx.tcx.lang_items().option_type() => {
args.type_at(0)
}
_ => static_ty,
};

// Get the expected symbol function signature
let lang_sig = cx.tcx.normalize_erasing_regions(
cx.typing_env(),
cx.tcx.fn_sig(expected_def_id).instantiate_identity(),
);

let expected = Ty::new_fn_ptr(cx.tcx, lang_sig);

// Compare the expected function signature with the static type, report an error if they don't match
if expected != inner_static_ty {
cx.emit_span_lint(
INVALID_RUNTIME_SYMBOL_DEFINITIONS,
sp,
RedefiningRuntimeSymbolsDiag::Static {
static_ty,
symbol_name: symbol_name.to_string(),
expected_fn_sig: expected,
},
);
}
}
8 changes: 5 additions & 3 deletions compiler/rustc_middle/src/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ impl EffectiveVisibility {
}
}

pub fn public_at_level(&self) -> Option<Level> {
Level::all_levels().into_iter().find(|&level| self.is_public_at_level(level))
}

pub fn is_public_at_level(&self, level: Level) -> bool {
self.at_level(level).is_public()
}
Expand Down Expand Up @@ -120,9 +124,7 @@ impl EffectiveVisibilities {
}

pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
self.effective_vis(id).and_then(|effective_vis| {
Level::all_levels().into_iter().find(|&level| effective_vis.is_public_at_level(level))
})
self.effective_vis(id).and_then(|effective_vis| effective_vis.public_at_level())
}

pub fn update_root(&mut self) {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ pub struct ResolverGlobalCtxt {
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
pub expn_that_defined: UnordMap<LocalDefId, ExpnId>,
pub effective_visibilities: EffectiveVisibilities,
// FIXME: This table contains ADTs reachable from macro 2.0.
// Currently, reachability of a definition from a macro is determined by nominal visibility
// (see `compute_effective_visibilities`). This is incorrect and leads to the necessity
// of traversing ADT fields in `rustc_privacy`. Remove this workaround once the
// correct reachability logic is implemented for macros.
pub macro_reachable_adts: FxIndexMap<LocalDefId, FxIndexSet<LocalDefId>>,
pub extern_crate_map: UnordMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub module_children: LocalDefIdMap<Vec<ModChild>>,
Expand Down
Loading
Loading