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
89d5059
Replace the first of 4 binary invocations for offload
ZuseZ4 Nov 21, 2025
88ca3bc
update dev guide
ZuseZ4 Nov 21, 2025
d340ea5
Fix ICE when collecting opaques from trait method declarations
lapla-cogito Nov 21, 2025
7f7b348
Introduce InlineAsmError type
bjorn3 Nov 11, 2025
bba5f7f
Remove unused pop_span_label method
bjorn3 Nov 21, 2025
2a28013
Allow passing primary spans to SharedEmitter
bjorn3 Nov 21, 2025
3ad8250
Add `rust-mingw` component for `*-windows-gnullvm`
mati865 Oct 1, 2025
f580357
Handle cycles when checking impl candidates for `doc(hidden)`
Jules-Bertholet Nov 21, 2025
3386da8
Move safe computation out of unsafe block
chirizxc Nov 21, 2025
8094934
Fix typo in HashMap performance comment
winningMove Nov 22, 2025
e2a69ce
Add `#[rustc_should_not_be_called_on_const_items]` attribute
Urgau Nov 2, 2025
0e8d1e1
Add `#[rustc_should_not_be_called_on_const_items]` to std methods
Urgau Nov 2, 2025
dc2a61e
Add `const_item_interior_mutations` lint
Urgau Nov 2, 2025
ddabb1c
Allow `const_item_interior_mutations` in Clippy tests
Urgau Nov 2, 2025
c48dce1
Allow `const_item_interior_mutations` in tests
Urgau Nov 2, 2025
421ed84
Rollup merge of #147536 - mati865:gnullvm-self-contained, r=petrochenkov
matthiaskrgr Nov 22, 2025
6e1ccd3
Rollup merge of #148407 - Urgau:suspicious_int_mutable_consts, r=Jona…
matthiaskrgr Nov 22, 2025
f15f149
Rollup merge of #149168 - lapla-cogito:ice_148622, r=tiif
matthiaskrgr Nov 22, 2025
565193a
Rollup merge of #149170 - ZuseZ4:automate-offload-packager, r=oli-obk
matthiaskrgr Nov 22, 2025
b7b04a2
Rollup merge of #149180 - bjorn3:lto_refactors9, r=dianqk
matthiaskrgr Nov 22, 2025
65619c8
Rollup merge of #149185 - Jules-Bertholet:fix-149092, r=chenyukang
matthiaskrgr Nov 22, 2025
587e448
Rollup merge of #149194 - chirizxc:patch-1, r=Noratrieb
matthiaskrgr Nov 22, 2025
1717388
Rollup merge of #149204 - winningMove:patch-1, r=chenyukang
matthiaskrgr Nov 22, 2025
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
11 changes: 11 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
}

pub(crate) struct RustcShouldNotBeCalledOnConstItems;
impl<S: Stage> NoArgsAttributeParser<S> for RustcShouldNotBeCalledOnConstItems {
const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcShouldNotBeCalledOnConstItems;
}

pub(crate) struct AutomaticallyDerivedParser;
impl<S: Stage> NoArgsAttributeParser<S> for AutomaticallyDerivedParser {
const PATH: &[Symbol] = &[sym::automatically_derived];
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::attributes::link_attrs::{
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
RustcShouldNotBeCalledOnConstItems,
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{
Expand Down Expand Up @@ -244,6 +245,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcMainParser>>,
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<TrackCallerParser>>,
Expand Down
23 changes: 18 additions & 5 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use libc::{c_char, c_int, c_void, size_t};
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::versioned_llvm_target;
use rustc_codegen_ssa::back::write::{
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
TargetMachineFactoryFn,
BitcodeSection, CodegenContext, EmitObj, InlineAsmError, ModuleConfig,
TargetMachineFactoryConfig, TargetMachineFactoryFn,
};
use rustc_codegen_ssa::base::wants_wasm_eh;
use rustc_codegen_ssa::traits::*;
Expand Down Expand Up @@ -434,7 +434,7 @@ fn report_inline_asm(
level: llvm::DiagnosticLevel,
cookie: u64,
source: Option<(String, Vec<InnerSpan>)>,
) {
) -> InlineAsmError {
// In LTO build we may get srcloc values from other crates which are invalid
// since they use a different source map. To be safe we just suppress these
// in LTO builds.
Expand All @@ -454,7 +454,7 @@ fn report_inline_asm(
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
let msg = msg.trim_prefix("error: ").to_string();
cgcx.diag_emitter.inline_asm_error(span, msg, level, source);
InlineAsmError { span, msg, level, source }
}

unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
Expand All @@ -466,7 +466,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void

match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } {
llvm::diagnostic::InlineAsm(inline) => {
report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
cgcx.diag_emitter.inline_asm_error(report_inline_asm(
cgcx,
inline.message,
inline.level,
inline.cookie,
inline.source,
));
}

llvm::diagnostic::Optimization(opt) => {
Expand Down Expand Up @@ -765,6 +771,13 @@ pub(crate) unsafe fn llvm_optimize(
llvm_plugins.len(),
)
};

if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) {
unsafe {
llvm::LLVMRustBundleImages(module.module_llvm.llmod(), module.module_llvm.tm.raw());
}
}

result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses))
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,9 @@ unsafe extern "C" {
Name: *const c_char,
) -> &'a Value;

/// Processes the module and writes it in an offload compatible way into a "host.out" file.
pub(crate) fn LLVMRustBundleImages<'a>(M: &'a Module, TM: &'a TargetMachine) -> bool;

/// Writes a module to the specified path. Returns 0 on success.
pub(crate) fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int;

Expand Down
40 changes: 23 additions & 17 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,7 @@ pub struct CguMessage;
// - `is_lint`: lints aren't relevant during codegen.
// - `emitted_at`: not used for codegen diagnostics.
struct Diagnostic {
span: Vec<SpanData>,
level: Level,
messages: Vec<(DiagMessage, Style)>,
code: Option<ErrCode>,
Expand All @@ -1218,7 +1219,7 @@ struct Diagnostic {
// A cut-down version of `rustc_errors::Subdiag` that impls `Send`. It's
// missing the following fields from `rustc_errors::Subdiag`.
// - `span`: it doesn't impl `Send`.
pub(crate) struct Subdiagnostic {
struct Subdiagnostic {
level: Level,
messages: Vec<(DiagMessage, Style)>,
}
Expand Down Expand Up @@ -1897,10 +1898,17 @@ fn spawn_thin_lto_work<'a, B: ExtraBackendMethods>(

enum SharedEmitterMessage {
Diagnostic(Diagnostic),
InlineAsmError(SpanData, String, Level, Option<(String, Vec<InnerSpan>)>),
InlineAsmError(InlineAsmError),
Fatal(String),
}

pub struct InlineAsmError {
pub span: SpanData,
pub msg: String,
pub level: Level,
pub source: Option<(String, Vec<InnerSpan>)>,
}

#[derive(Clone)]
pub struct SharedEmitter {
sender: Sender<SharedEmitterMessage>,
Expand All @@ -1917,14 +1925,8 @@ impl SharedEmitter {
(SharedEmitter { sender }, SharedEmitterMain { receiver })
}

pub fn inline_asm_error(
&self,
span: SpanData,
msg: String,
level: Level,
source: Option<(String, Vec<InnerSpan>)>,
) {
drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source)));
pub fn inline_asm_error(&self, err: InlineAsmError) {
drop(self.sender.send(SharedEmitterMessage::InlineAsmError(err)));
}

fn fatal(&self, msg: &str) {
Expand All @@ -1940,7 +1942,7 @@ impl Emitter for SharedEmitter {
) {
// Check that we aren't missing anything interesting when converting to
// the cut-down local `DiagInner`.
assert_eq!(diag.span, MultiSpan::new());
assert!(!diag.span.has_span_labels());
assert_eq!(diag.suggestions, Suggestions::Enabled(vec![]));
assert_eq!(diag.sort_span, rustc_span::DUMMY_SP);
assert_eq!(diag.is_lint, None);
Expand All @@ -1949,6 +1951,7 @@ impl Emitter for SharedEmitter {
let args = mem::replace(&mut diag.args, DiagArgMap::default());
drop(
self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
span: diag.span.primary_spans().iter().map(|span| span.data()).collect::<Vec<_>>(),
level: diag.level(),
messages: diag.messages,
code: diag.code,
Expand Down Expand Up @@ -1993,6 +1996,9 @@ impl SharedEmitterMain {
let dcx = sess.dcx();
let mut d =
rustc_errors::DiagInner::new_with_messages(diag.level, diag.messages);
d.span = MultiSpan::from_spans(
diag.span.into_iter().map(|span| span.span()).collect(),
);
d.code = diag.code; // may be `None`, that's ok
d.children = diag
.children
Expand All @@ -2007,15 +2013,15 @@ impl SharedEmitterMain {
dcx.emit_diagnostic(d);
sess.dcx().abort_if_errors();
}
Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => {
assert_matches!(level, Level::Error | Level::Warning | Level::Note);
let mut err = Diag::<()>::new(sess.dcx(), level, msg);
if !span.is_dummy() {
err.span(span.span());
Ok(SharedEmitterMessage::InlineAsmError(inner)) => {
assert_matches!(inner.level, Level::Error | Level::Warning | Level::Note);
let mut err = Diag::<()>::new(sess.dcx(), inner.level, inner.msg);
if !inner.span.is_dummy() {
err.span(inner.span.span());
}

// Point to the generated assembly if it is available.
if let Some((buffer, spans)) = source {
if let Some((buffer, spans)) = inner.source {
let source = sess
.source_map()
.new_source_file(FileName::inline_asm_source_code(&buffer), buffer);
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,6 @@ impl MultiSpan {
replacements_occurred
}

pub fn pop_span_label(&mut self) -> Option<(Span, DiagMessage)> {
self.span_labels.pop()
}

/// Returns the strings to highlight. We always ensure that there
/// is an entry for each of the primary spans -- for each primary
/// span `P`, if there is at least one label with span `P`, we return
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes,
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
),
rustc_attr!(
rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts."
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
RustcPassIndirectlyInNonRusticAbis(Span),

/// Represents `#[rustc_should_not_be_called_on_const_items]`
RustcShouldNotBeCalledOnConstItems(Span),

/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
RustcSimdMonomorphizeLaneLimit(Limit),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl AttributeKind {
RustcMain => No,
RustcObjectLifetimeDefault => No,
RustcPassIndirectlyInNonRusticAbis(..) => No,
RustcShouldNotBeCalledOnConstItems(..) => Yes,
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
Sanitize { .. } => No,
ShouldPanic { .. } => No,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
.current_use = this identifier can be confused with `{$existing_sym}`
.other_use = other identifier used here
lint_const_item_interior_mutations =
mutation of an interior mutable `const` item with call to `{$method_name}`
.label = `{$const_name}` is a interior mutable `const` item of type `{$const_ty}`
.temporary = each usage of a `const` item creates a new temporary
.never_original = only the temporaries and never the original `const {$const_name}` will be modified
.suggestion_static = for a shared instance of `{$const_name}`, consider making it a `static` item instead
.help = for more details on interior mutability see <https://doc.rust-lang.org/reference/interior-mutability.html>
lint_dangling_pointers_from_locals = {$fn_kind} returns a dangling pointer to dropped local variable `{$local_var_name}`
.ret_ty = return type is `{$ret_ty}`
.local_var = local variable `{$local_var_name}` is dropped at the end of the {$fn_kind}
Expand Down
122 changes: 122 additions & 0 deletions compiler/rustc_lint/src/interior_mutable_consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ItemKind, Node, find_attr};
use rustc_session::{declare_lint, declare_lint_pass};

use crate::lints::{ConstItemInteriorMutationsDiag, ConstItemInteriorMutationsSuggestionStatic};
use crate::{LateContext, LateLintPass, LintContext};

declare_lint! {
/// The `const_item_interior_mutations` lint checks for calls which
/// mutates an interior mutable const-item.
///
/// ### Example
///
/// ```rust
/// use std::sync::Once;
///
/// const INIT: Once = Once::new(); // using `INIT` will always create a temporary and
/// // never modify it-self on use, should be a `static`
/// // instead for shared use
///
/// fn init() {
/// INIT.call_once(|| {
/// println!("Once::call_once first call");
/// });
/// INIT.call_once(|| { // this second will also print
/// println!("Once::call_once second call"); // as each call to `INIT` creates
/// }); // new temporary
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Calling a method which mutates an interior mutable type has no effect as const-item
/// are essentially inlined wherever they are used, meaning that they are copied
/// directly into the relevant context when used rendering modification through
/// interior mutability ineffective across usage of that const-item.
///
/// The current implementation of this lint only warns on significant `std` and
/// `core` interior mutable types, like `Once`, `AtomicI32`, ... this is done out
/// of prudence to avoid false-positive and may be extended in the future.
pub CONST_ITEM_INTERIOR_MUTATIONS,
Warn,
"checks for calls which mutates a interior mutable const-item"
}

declare_lint_pass!(InteriorMutableConsts => [CONST_ITEM_INTERIOR_MUTATIONS]);

impl<'tcx> LateLintPass<'tcx> for InteriorMutableConsts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
let typeck = cx.typeck_results();

let (method_did, receiver) = match expr.kind {
// matching on `<receiver>.method(..)`
ExprKind::MethodCall(_, receiver, _, _) => {
(typeck.type_dependent_def_id(expr.hir_id), receiver)
}
// matching on `function(&<receiver>, ...)`
ExprKind::Call(path, [receiver, ..]) => match receiver.kind {
ExprKind::AddrOf(_, _, receiver) => match path.kind {
ExprKind::Path(ref qpath) => {
(cx.qpath_res(qpath, path.hir_id).opt_def_id(), receiver)
}
_ => return,
},
_ => return,
},
_ => return,
};

let Some(method_did) = method_did else {
return;
};

if let ExprKind::Path(qpath) = &receiver.kind
&& let Res::Def(DefKind::Const | DefKind::AssocConst, const_did) =
typeck.qpath_res(qpath, receiver.hir_id)
// Let's do the attribute check after the other checks for perf reasons
&& find_attr!(
cx.tcx.get_all_attrs(method_did),
AttributeKind::RustcShouldNotBeCalledOnConstItems(_)
)
&& let Some(method_name) = cx.tcx.opt_item_ident(method_did)
&& let Some(const_name) = cx.tcx.opt_item_ident(const_did)
&& let Some(const_ty) = typeck.node_type_opt(receiver.hir_id)
{
// Find the local `const`-item and create the suggestion to use `static` instead
let sugg_static = if let Some(Node::Item(const_item)) =
cx.tcx.hir_get_if_local(const_did)
&& let ItemKind::Const(ident, _generics, _ty, _body_id) = const_item.kind
{
if let Some(vis_span) = const_item.vis_span.find_ancestor_inside(const_item.span)
&& const_item.span.can_be_used_for_suggestions()
&& vis_span.can_be_used_for_suggestions()
{
Some(ConstItemInteriorMutationsSuggestionStatic::Spanful {
const_: const_item.vis_span.between(ident.span),
before: if !vis_span.is_empty() { " " } else { "" },
})
} else {
Some(ConstItemInteriorMutationsSuggestionStatic::Spanless)
}
} else {
None
};

cx.emit_span_lint(
CONST_ITEM_INTERIOR_MUTATIONS,
expr.span,
ConstItemInteriorMutationsDiag {
method_name,
const_name,
const_ty,
receiver_span: receiver.span,
sugg_static,
},
);
}
}
}
Loading
Loading