Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6bd5ab9
Emit error when self type is not specified and accessed
aerooneqq May 14, 2026
0f280d4
Add function to extract the symbol name from the attributes
Urgau Apr 19, 2026
8b67ab3
Add weak-only lang items for core runtime symbols
Urgau Apr 19, 2026
426706d
Add lint against invalid runtime symbol definitions
Urgau Apr 12, 2026
50306e1
Handle static whose type is a function pointer
Urgau Apr 19, 2026
453192d
Fix invalid `memcpy` definition in codegen test and UI tests
Urgau Apr 19, 2026
32aa35c
Fix invalid definition of `strlen` in error codes documentation
Urgau Apr 19, 2026
8f221d1
Test EII UI tests with prefer-dynamic
AsakuraMizu May 14, 2026
9faff71
actually run the temp_dir doctest
RalfJung May 12, 2026
8348c93
Fix `compiler-builtins` runtime symbols definitions
Urgau May 14, 2026
5a12d48
Prefer tracing::instrument.
cjgillot May 14, 2026
d76d4cd
Untuple method parameters.
cjgillot May 14, 2026
6e7b089
Use DropCtxt::new_block and new_block_with_statements systematically.
cjgillot May 14, 2026
85dfeda
Correctly handle associated items in rustdoc macro expansion
GuillaumeGomez May 14, 2026
899be9f
Add regression tests for associated items in rustdoc macro expansion
GuillaumeGomez May 14, 2026
8909e79
Require UTF-8 in `Utf8Pattern::StringPattern`
qaijuang May 13, 2026
13f5c66
Rollup merge of #155521 - Urgau:runtime-symbols, r=davidtwco
JonathanBrouwer May 15, 2026
63fde02
Rollup merge of #156493 - RalfJung:run-temp-dir, r=ChrisDenton
JonathanBrouwer May 15, 2026
9c06ef7
Rollup merge of #156556 - qaijuang:issue-156491-str-replace-utf8-patt…
JonathanBrouwer May 15, 2026
e847bd7
Rollup merge of #156565 - aerooneqq:delegation-self-type-ice, r=petro…
JonathanBrouwer May 15, 2026
a097925
Rollup merge of #156577 - AsakuraMizu:eii-default-dynamic, r=mejrs
JonathanBrouwer May 15, 2026
e117edf
Rollup merge of #156586 - cjgillot:elaborate-new-block, r=oli-obk
JonathanBrouwer May 15, 2026
2572fc8
Rollup merge of #156587 - GuillaumeGomez:assoc-items-macro-expansion,…
JonathanBrouwer May 15, 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
1 change: 1 addition & 0 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
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,
}
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_middle::ty::{
use rustc_span::{ErrorGuaranteed, Span, kw};

use crate::collect::ItemCtxt;
use crate::errors::DelegationSelfTypeNotSpecified;
use crate::hir_ty_lowering::HirTyLowerer;

type RemapTable = FxHashMap<u32, u32>;
Expand Down Expand Up @@ -284,6 +285,12 @@ fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) ->
ctx.lower_ty(tcx.hir_node(id).expect_ty())
})
.unwrap_or_else(|| {
// It is possible to attempt to get self type when it is used in signature
// (i.e., `fn default() -> Self`), so emit error here in addition to possible
// `mismatched types` error (see #156388).
let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) };
tcx.dcx().emit_err(err);

Ty::new_error_with_message(
tcx,
tcx.def_span(delegation_id),
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,14 @@ pub(crate) struct UnsupportedDelegation<'a> {
pub callee_span: Span,
}

#[derive(Diagnostic)]
#[diag("delegation self type is not specified")]
#[help("consider explicitly specifying self type: `reuse </* Type */ as Trait>::function`")]
pub(crate) struct DelegationSelfTypeNotSpecified {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("method should be `async` or return a future, but it is synchronous")]
pub(crate) struct MethodShouldReturnFuture {
Expand Down
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,
},
);
}
}
Loading
Loading