Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 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
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
9b368e3
Rollup merge of #147536 - mati865:gnullvm-self-contained, r=petrochenkov
matthiaskrgr Nov 22, 2025
3099ee9
Rollup merge of #148407 - Urgau:suspicious_int_mutable_consts, r=Jona…
matthiaskrgr Nov 22, 2025
39df71a
Rollup merge of #149168 - lapla-cogito:ice_148622, r=tiif
matthiaskrgr Nov 22, 2025
c08eb2d
Rollup merge of #149170 - ZuseZ4:automate-offload-packager, r=oli-obk
matthiaskrgr Nov 22, 2025
6fce771
Rollup merge of #149185 - Jules-Bertholet:fix-149092, r=chenyukang
matthiaskrgr Nov 22, 2025
819bcfa
Rollup merge of #149194 - chirizxc:patch-1, r=Noratrieb
matthiaskrgr Nov 22, 2025
41136e4
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
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,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
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,
},
);
}
}
}
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod foreign_modules;
mod function_cast_as_integer;
mod if_let_rescope;
mod impl_trait_overcaptures;
mod interior_mutable_consts;
mod internal;
mod invalid_from_utf8;
mod late;
Expand Down Expand Up @@ -93,6 +94,7 @@ use for_loops_over_fallibles::*;
use function_cast_as_integer::*;
use if_let_rescope::IfLetRescope;
use impl_trait_overcaptures::ImplTraitOvercaptures;
use interior_mutable_consts::*;
use internal::*;
use invalid_from_utf8::*;
use let_underscore::*;
Expand Down Expand Up @@ -239,6 +241,7 @@ late_lint_methods!(
AsyncClosureUsage: AsyncClosureUsage,
AsyncFnInTrait: AsyncFnInTrait,
NonLocalDefinitions: NonLocalDefinitions::default(),
InteriorMutableConsts: InteriorMutableConsts,
ImplTraitOvercaptures: ImplTraitOvercaptures,
IfLetRescope: IfLetRescope::default(),
StaticMutRefs: StaticMutRefs,
Expand Down
33 changes: 33 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,39 @@ pub(crate) enum InvalidFromUtf8Diag {
},
}

// interior_mutable_consts.rs
#[derive(LintDiagnostic)]
#[diag(lint_const_item_interior_mutations)]
#[note(lint_temporary)]
#[note(lint_never_original)]
#[help]
pub(crate) struct ConstItemInteriorMutationsDiag<'tcx> {
pub method_name: Ident,
pub const_name: Ident,
pub const_ty: Ty<'tcx>,
#[label]
pub receiver_span: Span,
#[subdiagnostic]
pub sugg_static: Option<ConstItemInteriorMutationsSuggestionStatic>,
}

#[derive(Subdiagnostic)]
pub(crate) enum ConstItemInteriorMutationsSuggestionStatic {
#[suggestion(
lint_suggestion_static,
code = "{before}static ",
style = "verbose",
applicability = "maybe-incorrect"
)]
Spanful {
#[primary_span]
const_: Span,
before: &'static str,
},
#[help(lint_suggestion_static)]
Spanless,
}

// reference_casting.rs
#[derive(LintDiagnostic)]
pub(crate) enum InvalidReferenceCastingDiag<'tcx> {
Expand Down
47 changes: 47 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/OffloadBinary.h"
#include "llvm/Remarks/RemarkFormat.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Remarks/RemarkStreamer.h"
Expand All @@ -35,6 +36,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <iostream>
Expand Down Expand Up @@ -144,6 +146,51 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) {
llvm::PrintStatistics(OS);
}

static Error writeFile(StringRef Filename, StringRef Data) {
Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
FileOutputBuffer::create(Filename, Data.size());
if (!OutputOrErr)
return OutputOrErr.takeError();
std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
llvm::copy(Data, Output->getBufferStart());
if (Error E = Output->commit())
return E;
return Error::success();
}

// This is the first of many steps in creating a binary using llvm offload,
// to run code on the gpu. Concrete, it replaces the following binary use:
// clang-offload-packager -o host.out
// --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp
// The input module is the rust code compiled for a gpu target like amdgpu.
// Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp
extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) {
std::string Storage;
llvm::raw_string_ostream OS1(Storage);
llvm::WriteBitcodeToFile(*unwrap(M), OS1);
OS1.flush();
auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "module.bc");

SmallVector<char, 1024> BinaryData;
raw_svector_ostream OS2(BinaryData);

OffloadBinary::OffloadingImage ImageBinary{};
ImageBinary.TheImageKind = object::IMG_Bitcode;
ImageBinary.Image = std::move(MB);
ImageBinary.TheOffloadKind = object::OFK_OpenMP;
ImageBinary.StringData["triple"] = TM.getTargetTriple().str();
ImageBinary.StringData["arch"] = TM.getTargetCPU();
llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary);
if (Buffer.size() % OffloadBinary::getAlignment() != 0)
// Offload binary has invalid size alignment
return false;
OS2 << Buffer;
if (Error E = writeFile("host.out",
StringRef(BinaryData.begin(), BinaryData.size())))
return false;
return true;
}

extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) {
llvm::Function *oldFn = llvm::unwrap<llvm::Function>(OldFn);
llvm::Function *newFn = llvm::unwrap<llvm::Function>(NewFn);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
| AttributeKind::ExportStable
| AttributeKind::FfiConst(..)
| AttributeKind::UnstableFeatureBound(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,7 @@ symbols! {
rustc_regions,
rustc_reservation_impl,
rustc_serialize,
rustc_should_not_be_called_on_const_items,
rustc_simd_monomorphize_lane_limit,
rustc_skip_during_method_dispatch,
rustc_specialization_trait,
Expand Down
Loading
Loading