Skip to content

Rollup of 8 pull requests #140256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Apr 24, 2025
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eda9973
Add `#[repr(u128)]`/`#[repr(i128)]` enums to `improper_ctypes_definit…
beetrees Mar 9, 2025
75f86e6
fix LooseTypes flag and PrintMod behaviour, add debug helper
ZuseZ4 Apr 12, 2025
31578dc
fix "could not find source function" error by preventing function mer…
ZuseZ4 Apr 12, 2025
5ea9125
update documentation
ZuseZ4 Apr 12, 2025
f79a992
add tests for merge_function handling
ZuseZ4 Apr 12, 2025
2ef4f78
rustc_target: Adjust RISC-V feature implication
a4lg Apr 22, 2025
dfc8f02
Move zkVM constants into `sys::env_consts`
thaliaarchi Apr 22, 2025
0296f05
Make algebraic intrinsics into 'const fn' items; Make algebraic funct…
bjoernager Apr 22, 2025
a4b9a1b
Remove `git_repository` field from `GitConfig`
Kobzol Apr 23, 2025
91da45a
Remove `git_repository` from the `stage0` file
Kobzol Apr 23, 2025
157caee
fix f*::MAX_EXP and MIN_EXP docs
RalfJung Apr 22, 2025
c8c0742
Suggest {to,from}_ne_bytes for transmutations between arrays and inte…
bend-n Mar 31, 2025
6921a51
stdarch
bend-n Apr 18, 2025
53afa97
Rollup merge of #136083 - bend-n:⃤⃤, r=lcnr
matthiaskrgr Apr 24, 2025
27eac4b
Rollup merge of #138282 - beetrees:repr128-not-ffi-safe, r=oli-obk
matthiaskrgr Apr 24, 2025
c3f811f
Rollup merge of #139700 - EnzymeAD:autodiff-flags, r=oli-obk
matthiaskrgr Apr 24, 2025
31a72bc
Rollup merge of #140139 - a4lg:riscv-feature-imply-adjust-1, r=Amanieu
matthiaskrgr Apr 24, 2025
9dcb367
Rollup merge of #140141 - thaliaarchi:env-consts/zkvm, r=joboet
matthiaskrgr Apr 24, 2025
06126df
Rollup merge of #140150 - RalfJung:MAX_EXP, r=tgross35
matthiaskrgr Apr 24, 2025
cea6ba7
Rollup merge of #140172 - bjoernager:const-float-algebraic, r=RalfJung
matthiaskrgr Apr 24, 2025
a016552
Rollup merge of #140191 - Kobzol:remove-git-repository-from-git-confi…
matthiaskrgr Apr 24, 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
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/example/example.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(no_core, unboxed_closures)]
#![no_core]
#![allow(dead_code)]
#![allow(dead_code, unnecessary_transmutes)]

extern crate mini_core;

8 changes: 2 additions & 6 deletions compiler/rustc_codegen_gcc/example/example.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(no_core, unboxed_closures)]
#![no_core]
#![allow(dead_code)]
#![allow(dead_code, unnecessary_transmutes)]

extern crate mini_core;

@@ -11,11 +11,7 @@ fn abc(a: u8) -> u8 {
}

fn bcd(b: bool, a: u8) -> u8 {
if b {
a * 2
} else {
a * 3
}
if b { a * 2 } else { a * 3 }
}

fn call() {
40 changes: 22 additions & 18 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
@@ -584,12 +584,10 @@ fn thin_lto(
}
}

fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen<ModuleLlvm>) {
fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
for &val in ad {
// We intentionally don't use a wildcard, to not forget handling anything new.
match val {
config::AutoDiff::PrintModBefore => {
unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) };
}
config::AutoDiff::PrintPerf => {
llvm::set_print_perf(true);
}
@@ -603,17 +601,23 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen<
llvm::set_inline(true);
}
config::AutoDiff::LooseTypes => {
llvm::set_loose_types(false);
llvm::set_loose_types(true);
}
config::AutoDiff::PrintSteps => {
llvm::set_print(true);
}
// We handle this below
// We handle this in the PassWrapper.cpp
config::AutoDiff::PrintPasses => {}
// We handle this in the PassWrapper.cpp
config::AutoDiff::PrintModBefore => {}
// We handle this in the PassWrapper.cpp
config::AutoDiff::PrintModAfter => {}
// We handle this below
// We handle this in the PassWrapper.cpp
config::AutoDiff::PrintModFinal => {}
// This is required and already checked
config::AutoDiff::Enable => {}
// We handle this below
config::AutoDiff::NoPostopt => {}
}
}
// This helps with handling enums for now.
@@ -647,27 +651,27 @@ pub(crate) fn run_pass_manager(
// We then run the llvm_optimize function a second time, to optimize the code which we generated
// in the enzyme differentiation pass.
let enable_ad = config.autodiff.contains(&config::AutoDiff::Enable);
let stage =
if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD };
let stage = if thin {
write::AutodiffStage::PreAD
} else {
if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD }
};

if enable_ad {
enable_autodiff_settings(&config.autodiff, module);
enable_autodiff_settings(&config.autodiff);
}

unsafe {
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
}

if cfg!(llvm_enzyme) && enable_ad {
// This is the post-autodiff IR, mainly used for testing and educational purposes.
if config.autodiff.contains(&config::AutoDiff::PrintModAfter) {
unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) };
}

if cfg!(llvm_enzyme) && enable_ad && !thin {
let opt_stage = llvm::OptStage::FatLTO;
let stage = write::AutodiffStage::PostAD;
unsafe {
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {
unsafe {
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
}
}

// This is the final IR, so people should be able to inspect the optimized autodiff output,
16 changes: 15 additions & 1 deletion compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
@@ -572,20 +572,31 @@ pub(crate) unsafe fn llvm_optimize(

let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
let run_enzyme = autodiff_stage == AutodiffStage::DuringAD;
let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore);
let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter);
let print_passes = config.autodiff.contains(&config::AutoDiff::PrintPasses);
let merge_functions;
let unroll_loops;
let vectorize_slp;
let vectorize_loop;

// When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
// optimizations until after differentiation. Our pipeline is thus: (opt + enzyme), (full opt).
// We therefore have two calls to llvm_optimize, if autodiff is used.
//
// We also must disable merge_functions, since autodiff placeholder/dummy bodies tend to be
// identical. We run opts before AD, so there is a chance that LLVM will merge our dummies.
// In that case, we lack some dummy bodies and can't replace them with the real AD code anymore.
// We then would need to abort compilation. This was especially common in test cases.
if consider_ad && autodiff_stage != AutodiffStage::PostAD {
merge_functions = false;
unroll_loops = false;
vectorize_slp = false;
vectorize_loop = false;
} else {
unroll_loops =
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
merge_functions = config.merge_functions;
vectorize_slp = config.vectorize_slp;
vectorize_loop = config.vectorize_loop;
}
@@ -663,13 +674,16 @@ pub(crate) unsafe fn llvm_optimize(
thin_lto_buffer,
config.emit_thin_lto,
config.emit_thin_lto_summary,
config.merge_functions,
merge_functions,
unroll_loops,
vectorize_slp,
vectorize_loop,
config.no_builtins,
config.emit_lifetime_markers,
run_enzyme,
print_before_enzyme,
print_after_enzyme,
print_passes,
sanitizer_options.as_ref(),
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/builder/autodiff.rs
Original file line number Diff line number Diff line change
@@ -473,7 +473,7 @@ pub(crate) fn differentiate<'ll>(
return Err(diag_handler.handle().emit_almost_fatal(AutoDiffWithoutEnable));
}

// Before dumping the module, we want all the TypeTrees to become part of the module.
// Here we replace the placeholder code with the actual autodiff code, which calls Enzyme.
for item in diff_items.iter() {
let name = item.source.clone();
let fn_def: Option<&llvm::Value> = cx.get_function(&name);
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -2454,6 +2454,9 @@ unsafe extern "C" {
DisableSimplifyLibCalls: bool,
EmitLifetimeMarkers: bool,
RunEnzyme: bool,
PrintBeforeEnzyme: bool,
PrintAfterEnzyme: bool,
PrintPasses: bool,
SanitizerOptions: Option<&SanitizerOptions>,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char,
25 changes: 25 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -158,6 +158,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.copy_op(&val, dest)?;
}

sym::fadd_algebraic
| sym::fsub_algebraic
| sym::fmul_algebraic
| sym::fdiv_algebraic
| sym::frem_algebraic => {
let a = self.read_immediate(&args[0])?;
let b = self.read_immediate(&args[1])?;

let op = match intrinsic_name {
sym::fadd_algebraic => BinOp::Add,
sym::fsub_algebraic => BinOp::Sub,
sym::fmul_algebraic => BinOp::Mul,
sym::fdiv_algebraic => BinOp::Div,
sym::frem_algebraic => BinOp::Rem,

_ => bug!(),
};

let res = self.binary_op(op, &a, &b)?;
// `binary_op` already called `generate_nan` if needed.

// FIXME: Miri should add some non-determinism to the result here to catch any dependences on exact computations. This has previously been done, but the behaviour was removed as part of constification.
self.write_immediate(*res, dest)?;
}

sym::ctpop
| sym::cttz
| sym::cttz_nonzero
12 changes: 11 additions & 1 deletion compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::iter;
use std::ops::ControlFlow;

use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
use rustc_abi::{
BackendRepr, Integer, IntegerType, TagEncoding, VariantIdx, Variants, WrappingRange,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage;
use rustc_hir::intravisit::VisitorExt;
@@ -1243,6 +1245,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}

if let Some(IntegerType::Fixed(Integer::I128, _)) = def.repr().int {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_128bit,
help: None,
};
}

use improper_ctypes::check_non_exhaustive_variant;

let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
25 changes: 25 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -117,6 +117,7 @@ declare_lint_pass! {
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
UNNAMEABLE_TEST_ITEMS,
UNNAMEABLE_TYPES,
UNNECESSARY_TRANSMUTES,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
UNSAFE_ATTR_OUTSIDE_UNSAFE,
@@ -4909,6 +4910,30 @@ declare_lint! {
"detects pointer to integer transmutes in const functions and associated constants",
}

declare_lint! {
/// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives.
///
/// ### Example
///
/// ```rust
/// fn bytes_at_home(x: [u8; 4]) -> u32 {
/// unsafe { std::mem::transmute(x) }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Using an explicit method is preferable over calls to
/// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as
/// they more clearly communicate the intent, are easier to review, and
/// are less likely to accidentally result in unsoundness.
pub UNNECESSARY_TRANSMUTES,
Warn,
"detects transmutes that are shadowed by std methods"
}

declare_lint! {
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
/// that runs a custom `Drop` destructor.
30 changes: 28 additions & 2 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRPrinter/IRPrintingPasses.h"
#include "llvm/LTO/LTO.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
@@ -703,7 +704,8 @@ extern "C" LLVMRustResult LLVMRustOptimize(
bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO,
bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops,
bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls,
bool EmitLifetimeMarkers, bool RunEnzyme,
bool EmitLifetimeMarkers, bool RunEnzyme, bool PrintBeforeEnzyme,
bool PrintAfterEnzyme, bool PrintPasses,
LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath,
const char *PGOUsePath, bool InstrumentCoverage,
const char *InstrProfileOutput, const char *PGOSampleUsePath,
@@ -1048,14 +1050,38 @@ extern "C" LLVMRustResult LLVMRustOptimize(
// now load "-enzyme" pass:
#ifdef ENZYME
if (RunEnzyme) {
registerEnzymeAndPassPipeline(PB, true);

if (PrintBeforeEnzyme) {
// Handle the Rust flag `-Zautodiff=PrintModBefore`.
std::string Banner = "Module before EnzymeNewPM";
MPM.addPass(PrintModulePass(outs(), Banner, true, false));
}

registerEnzymeAndPassPipeline(PB, false);
if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) {
std::string ErrMsg = toString(std::move(Err));
LLVMRustSetLastError(ErrMsg.c_str());
return LLVMRustResult::Failure;
}

if (PrintAfterEnzyme) {
// Handle the Rust flag `-Zautodiff=PrintModAfter`.
std::string Banner = "Module after EnzymeNewPM";
MPM.addPass(PrintModulePass(outs(), Banner, true, false));
}
}
#endif
if (PrintPasses) {
// Print all passes from the PM:
std::string Pipeline;
raw_string_ostream SOS(Pipeline);
MPM.printPipeline(SOS, [&PIC](StringRef ClassName) {
auto PassName = PIC.getPassNameForClassName(ClassName);
return PassName.empty() ? ClassName : PassName;
});
outs() << Pipeline;
outs() << "\n";
}

// Upgrade all calls to old intrinsics first.
for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;)
1 change: 1 addition & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
@@ -84,3 +84,4 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
mir_transform_unnecessary_transmute = unnecessary transmute
100 changes: 100 additions & 0 deletions compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind};
use rustc_middle::ty::*;
use rustc_session::lint::builtin::UNNECESSARY_TRANSMUTES;
use rustc_span::source_map::Spanned;
use rustc_span::{Span, sym};

use crate::errors::UnnecessaryTransmute as Error;

/// Check for transmutes that overlap with stdlib methods.
/// For example, transmuting `[u8; 4]` to `u32`.
pub(super) struct CheckUnnecessaryTransmutes;

impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = UnnecessaryTransmuteChecker { body, tcx };
checker.visit_body(body);
}
}

struct UnnecessaryTransmuteChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
}

impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
fn is_unnecessary_transmute(
&self,
function: &Operand<'tcx>,
arg: String,
span: Span,
) -> Option<Error> {
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
let [input] = fn_sig.inputs() else { return None };

let err = |sugg| Error { span, sugg, help: None };

Some(match (input.kind(), fn_sig.output().kind()) {
// dont check the length; transmute does that for us.
// [u8; _] => primitive
(Array(t, _), Uint(_) | Float(_) | Int(_)) if *t.kind() == Uint(UintTy::U8) => Error {
sugg: format!("{}::from_ne_bytes({arg})", fn_sig.output()),
help: Some(
"there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order",
),
span,
},
// primitive => [u8; _]
(Uint(_) | Float(_) | Int(_), Array(t, _)) if *t.kind() == Uint(UintTy::U8) => Error {
sugg: format!("{input}::to_ne_bytes({arg})"),
help: Some(
"there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order",
),
span,
},
// char → u32
(Char, Uint(UintTy::U32)) => err(format!("u32::from({arg})")),
// u32 → char
(Uint(UintTy::U32), Char) => Error {
sugg: format!("char::from_u32_unchecked({arg})"),
help: Some("consider `char::from_u32(…).unwrap()`"),
span,
},
// uNN → iNN
(Uint(ty), Int(_)) => err(format!("{}::cast_signed({arg})", ty.name_str())),
// iNN → uNN
(Int(ty), Uint(_)) => err(format!("{}::cast_unsigned({arg})", ty.name_str())),
// fNN → uNN
(Float(ty), Uint(..)) => err(format!("{}::to_bits({arg})", ty.name_str())),
// uNN → fNN
(Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())),
// bool → { x8 }
(Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())),
// u8 → bool
(Uint(_), Bool) => err(format!("({arg} == 1)")),
_ => return None,
})
}
}

impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> {
// Check each block's terminator for calls to pointer to integer transmutes
// in const functions or associated constants and emit a lint.
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
if let TerminatorKind::Call { func, args, .. } = &terminator.kind
&& let [Spanned { span: arg, .. }] = **args
&& let Some((func_def_id, _)) = func.const_fn_def()
&& self.tcx.is_intrinsic(func_def_id, sym::transmute)
&& let span = self.body.source_info(location).span
&& let Some(lint) = self.is_unnecessary_transmute(
func,
self.tcx.sess.source_map().span_to_snippet(arg).expect("ok"),
span,
)
&& let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes)
{
self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint);
}
}
}
20 changes: 20 additions & 0 deletions compiler/rustc_mir_transform/src/errors.rs
Original file line number Diff line number Diff line change
@@ -158,6 +158,26 @@ pub(crate) struct MustNotSuspendReason {
pub reason: String,
}

pub(crate) struct UnnecessaryTransmute {
pub span: Span,
pub sugg: String,
pub help: Option<&'static str>,
}

// Needed for def_path_str
impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute {
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
diag.primary_message(fluent::mir_transform_unnecessary_transmute);
diag.span_suggestion(
self.span,
"replace this with",
self.sugg,
lint::Applicability::MachineApplicable,
);
self.help.map(|help| diag.help(help));
}
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_undefined_transmute)]
#[note]
2 changes: 2 additions & 0 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
@@ -125,6 +125,7 @@ declare_passes! {
mod check_null : CheckNull;
mod check_packed_ref : CheckPackedRef;
mod check_undefined_transmutes : CheckUndefinedTransmutes;
mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod cleanup_post_borrowck : CleanupPostBorrowck;

@@ -391,6 +392,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
&Lint(check_const_item_mutation::CheckConstItemMutation),
&Lint(function_item_references::FunctionItemReferences),
&Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
&Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::Initial,
&Lint(sanity_check::SanityCheck),
4 changes: 4 additions & 0 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -246,6 +246,10 @@ pub enum AutoDiff {
/// Print the module after running autodiff and optimizations.
PrintModFinal,

/// Print all passes scheduled by LLVM
PrintPasses,
/// Disable extra opt run after running autodiff
NoPostopt,
/// Enzyme's loose type debug helper (can cause incorrect gradients!!)
/// Usable in cases where Enzyme errors with `can not deduce type of X`.
LooseTypes,
6 changes: 5 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
@@ -711,7 +711,7 @@ mod desc {
pub(crate) const parse_list: &str = "a space-separated list of strings";
pub(crate) const parse_list_with_polarity: &str =
"a comma-separated list of strings, with elements beginning with + or -";
pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `LooseTypes`, `Inline`";
pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`";
pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
pub(crate) const parse_number: &str = "a number";
@@ -1360,6 +1360,8 @@ pub mod parse {
"PrintModBefore" => AutoDiff::PrintModBefore,
"PrintModAfter" => AutoDiff::PrintModAfter,
"PrintModFinal" => AutoDiff::PrintModFinal,
"NoPostopt" => AutoDiff::NoPostopt,
"PrintPasses" => AutoDiff::PrintPasses,
"LooseTypes" => AutoDiff::LooseTypes,
"Inline" => AutoDiff::Inline,
_ => {
@@ -2098,6 +2100,8 @@ options! {
`=PrintModBefore`
`=PrintModAfter`
`=PrintModFinal`
`=PrintPasses`,
`=NoPostopt`
`=LooseTypes`
`=Inline`
Multiple options can be combined with commas."),
10 changes: 5 additions & 5 deletions compiler/rustc_target/src/target_features.rs
Original file line number Diff line number Diff line change
@@ -516,7 +516,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("zawrs", Unstable(sym::riscv_target_feature), &[]),
("zba", Stable, &[]),
("zbb", Stable, &[]),
("zbc", Stable, &[]),
("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc
("zbkb", Stable, &[]),
("zbkc", Stable, &[]),
("zbkx", Stable, &[]),
@@ -545,20 +545,20 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("zknd", Stable, &[]),
("zkne", Stable, &[]),
("zknh", Stable, &[]),
("zkr", Stable, &["zicsr"]),
("zkr", Stable, &[]),
("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
("zksed", Stable, &[]),
("zksh", Stable, &[]),
("zkt", Stable, &[]),
("ztso", Unstable(sym::riscv_target_feature), &[]),
("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]),
("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb
("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]),
("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]),
("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]),
("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]),
("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zfhmin"]),
("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin
("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]),
("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]),
@@ -567,7 +567,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]),
("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]),
("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]),
("zvknhb", Unstable(sym::riscv_target_feature), &["zve64x"]),
("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha
("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]),
("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]),
("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]),
1 change: 1 addition & 0 deletions library/alloctests/tests/fmt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![deny(warnings)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
#![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]

use std::cell::RefCell;
use std::fmt::{self, Write};
2 changes: 2 additions & 0 deletions library/core/src/char/convert.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ pub(super) const fn from_u32(i: u32) -> Option<char> {
/// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`].
#[inline]
#[must_use]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
// SAFETY: the caller must guarantee that `i` is a valid char value.
unsafe {
@@ -221,6 +222,7 @@ impl FromStr for char {
}

#[inline]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
const fn char_try_from_u32(i: u32) -> Result<char, CharTryFromError> {
// This is an optimized version of the check
// (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF),
11 changes: 6 additions & 5 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
@@ -1497,6 +1497,7 @@ pub const fn forget<T: ?Sized>(_: T);
/// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.:
///
/// ```
/// # #![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
/// let raw_bytes = [0x78, 0x56, 0x34, 0x12];
///
/// let num = unsafe {
@@ -2429,35 +2430,35 @@ pub unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> In
/// Stabilized as [`f16::algebraic_add`], [`f32::algebraic_add`], [`f64::algebraic_add`] and [`f128::algebraic_add`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub fn fadd_algebraic<T: Copy>(a: T, b: T) -> T;
pub const fn fadd_algebraic<T: Copy>(a: T, b: T) -> T;

/// Float subtraction that allows optimizations based on algebraic rules.
///
/// Stabilized as [`f16::algebraic_sub`], [`f32::algebraic_sub`], [`f64::algebraic_sub`] and [`f128::algebraic_sub`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub fn fsub_algebraic<T: Copy>(a: T, b: T) -> T;
pub const fn fsub_algebraic<T: Copy>(a: T, b: T) -> T;

/// Float multiplication that allows optimizations based on algebraic rules.
///
/// Stabilized as [`f16::algebraic_mul`], [`f32::algebraic_mul`], [`f64::algebraic_mul`] and [`f128::algebraic_mul`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub fn fmul_algebraic<T: Copy>(a: T, b: T) -> T;
pub const fn fmul_algebraic<T: Copy>(a: T, b: T) -> T;

/// Float division that allows optimizations based on algebraic rules.
///
/// Stabilized as [`f16::algebraic_div`], [`f32::algebraic_div`], [`f64::algebraic_div`] and [`f128::algebraic_div`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub fn fdiv_algebraic<T: Copy>(a: T, b: T) -> T;
pub const fn fdiv_algebraic<T: Copy>(a: T, b: T) -> T;

/// Float remainder that allows optimizations based on algebraic rules.
///
/// Stabilized as [`f16::algebraic_rem`], [`f32::algebraic_rem`], [`f64::algebraic_rem`] and [`f128::algebraic_rem`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub fn frem_algebraic<T: Copy>(a: T, b: T) -> T;
pub const fn frem_algebraic<T: Copy>(a: T, b: T) -> T;

/// Returns the number of bits set in an integer type `T`
///
35 changes: 24 additions & 11 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
@@ -197,16 +197,22 @@ impl f128 {
#[unstable(feature = "f128", issue = "116909")]
pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;

/// One greater than the minimum possible normal power of 2 exponent.
/// One greater than the minimum possible *normal* power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MIN_EXP`, then normal numbers
/// ≥&nbsp;0.5&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact minimum possible *normal* power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all normal numbers representable by this type are
/// greater than or equal to 0.5&nbsp;×&nbsp;2<sup><i>MIN_EXP</i></sup>.
#[unstable(feature = "f128", issue = "116909")]
pub const MIN_EXP: i32 = -16_381;
/// Maximum possible power of 2 exponent.
/// One greater than the maximum possible power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MAX_EXP`, then normal numbers
/// &lt;&nbsp;1&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact maximum possible power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all numbers representable by this type are
/// strictly less than 2<sup><i>MAX_EXP</i></sup>.
#[unstable(feature = "f128", issue = "116909")]
pub const MAX_EXP: i32 = 16_384;

@@ -904,6 +910,7 @@ impl f128 {
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn to_bits(self) -> u128 {
// SAFETY: `u128` is a plain old datatype so we can always transmute to it.
unsafe { mem::transmute(self) }
@@ -951,6 +958,7 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn from_bits(v: u128) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u128` is a plain old datatype so we can always transmute from it.
@@ -1374,8 +1382,9 @@ impl f128 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_add(self, rhs: f128) -> f128 {
pub const fn algebraic_add(self, rhs: f128) -> f128 {
intrinsics::fadd_algebraic(self, rhs)
}

@@ -1384,8 +1393,9 @@ impl f128 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_sub(self, rhs: f128) -> f128 {
pub const fn algebraic_sub(self, rhs: f128) -> f128 {
intrinsics::fsub_algebraic(self, rhs)
}

@@ -1394,8 +1404,9 @@ impl f128 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_mul(self, rhs: f128) -> f128 {
pub const fn algebraic_mul(self, rhs: f128) -> f128 {
intrinsics::fmul_algebraic(self, rhs)
}

@@ -1404,8 +1415,9 @@ impl f128 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_div(self, rhs: f128) -> f128 {
pub const fn algebraic_div(self, rhs: f128) -> f128 {
intrinsics::fdiv_algebraic(self, rhs)
}

@@ -1414,8 +1426,9 @@ impl f128 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_rem(self, rhs: f128) -> f128 {
pub const fn algebraic_rem(self, rhs: f128) -> f128 {
intrinsics::frem_algebraic(self, rhs)
}
}
35 changes: 24 additions & 11 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
@@ -192,16 +192,22 @@ impl f16 {
#[unstable(feature = "f16", issue = "116909")]
pub const MAX: f16 = 6.5504e+4_f16;

/// One greater than the minimum possible normal power of 2 exponent.
/// One greater than the minimum possible *normal* power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MIN_EXP`, then normal numbers
/// ≥&nbsp;0.5&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact minimum possible *normal* power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all normal numbers representable by this type are
/// greater than or equal to 0.5&nbsp;×&nbsp;2<sup><i>MIN_EXP</i></sup>.
#[unstable(feature = "f16", issue = "116909")]
pub const MIN_EXP: i32 = -13;
/// Maximum possible power of 2 exponent.
/// One greater than the maximum possible power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MAX_EXP`, then normal numbers
/// &lt;&nbsp;1&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact maximum possible power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all numbers representable by this type are
/// strictly less than 2<sup><i>MAX_EXP</i></sup>.
#[unstable(feature = "f16", issue = "116909")]
pub const MAX_EXP: i32 = 16;

@@ -892,6 +898,7 @@ impl f16 {
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn to_bits(self) -> u16 {
// SAFETY: `u16` is a plain old datatype so we can always transmute to it.
unsafe { mem::transmute(self) }
@@ -938,6 +945,7 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn from_bits(v: u16) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u16` is a plain old datatype so we can always transmute from it.
@@ -1350,8 +1358,9 @@ impl f16 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_add(self, rhs: f16) -> f16 {
pub const fn algebraic_add(self, rhs: f16) -> f16 {
intrinsics::fadd_algebraic(self, rhs)
}

@@ -1360,8 +1369,9 @@ impl f16 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_sub(self, rhs: f16) -> f16 {
pub const fn algebraic_sub(self, rhs: f16) -> f16 {
intrinsics::fsub_algebraic(self, rhs)
}

@@ -1370,8 +1380,9 @@ impl f16 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_mul(self, rhs: f16) -> f16 {
pub const fn algebraic_mul(self, rhs: f16) -> f16 {
intrinsics::fmul_algebraic(self, rhs)
}

@@ -1380,8 +1391,9 @@ impl f16 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_div(self, rhs: f16) -> f16 {
pub const fn algebraic_div(self, rhs: f16) -> f16 {
intrinsics::fdiv_algebraic(self, rhs)
}

@@ -1390,8 +1402,9 @@ impl f16 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_rem(self, rhs: f16) -> f16 {
pub const fn algebraic_rem(self, rhs: f16) -> f16 {
intrinsics::frem_algebraic(self, rhs)
}
}
38 changes: 25 additions & 13 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
@@ -443,16 +443,22 @@ impl f32 {
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MAX: f32 = 3.40282347e+38_f32;

/// One greater than the minimum possible normal power of 2 exponent.
/// One greater than the minimum possible *normal* power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MIN_EXP`, then normal numbers
/// ≥&nbsp;0.5&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact minimum possible *normal* power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all normal numbers representable by this type are
/// greater than or equal to 0.5&nbsp;×&nbsp;2<sup><i>MIN_EXP</i></sup>.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MIN_EXP: i32 = -125;
/// Maximum possible power of 2 exponent.
/// One greater than the maximum possible power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MAX_EXP`, then normal numbers
/// &lt;&nbsp;1&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact maximum possible power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all numbers representable by this type are
/// strictly less than 2<sup><i>MAX_EXP</i></sup>.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MAX_EXP: i32 = 128;

@@ -710,8 +716,7 @@ impl f32 {
pub const fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
// applies to zeros and NaNs as well.
// SAFETY: This is just transmuting to get the sign bit, it's fine.
unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 }
self.to_bits() & 0x8000_0000 != 0
}

/// Returns the least number greater than `self`.
@@ -1097,6 +1102,7 @@ impl f32 {
#[stable(feature = "float_bits_conv", since = "1.20.0")]
#[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")]
#[inline]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn to_bits(self) -> u32 {
// SAFETY: `u32` is a plain old datatype so we can always transmute to it.
unsafe { mem::transmute(self) }
@@ -1142,6 +1148,7 @@ impl f32 {
#[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")]
#[must_use]
#[inline]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn from_bits(v: u32) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u32` is a plain old datatype so we can always transmute from it.
@@ -1516,8 +1523,9 @@ impl f32 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_add(self, rhs: f32) -> f32 {
pub const fn algebraic_add(self, rhs: f32) -> f32 {
intrinsics::fadd_algebraic(self, rhs)
}

@@ -1526,8 +1534,9 @@ impl f32 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_sub(self, rhs: f32) -> f32 {
pub const fn algebraic_sub(self, rhs: f32) -> f32 {
intrinsics::fsub_algebraic(self, rhs)
}

@@ -1536,8 +1545,9 @@ impl f32 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_mul(self, rhs: f32) -> f32 {
pub const fn algebraic_mul(self, rhs: f32) -> f32 {
intrinsics::fmul_algebraic(self, rhs)
}

@@ -1546,8 +1556,9 @@ impl f32 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_div(self, rhs: f32) -> f32 {
pub const fn algebraic_div(self, rhs: f32) -> f32 {
intrinsics::fdiv_algebraic(self, rhs)
}

@@ -1556,8 +1567,9 @@ impl f32 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_rem(self, rhs: f32) -> f32 {
pub const fn algebraic_rem(self, rhs: f32) -> f32 {
intrinsics::frem_algebraic(self, rhs)
}
}
38 changes: 25 additions & 13 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
@@ -442,16 +442,22 @@ impl f64 {
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MAX: f64 = 1.7976931348623157e+308_f64;

/// One greater than the minimum possible normal power of 2 exponent.
/// One greater than the minimum possible *normal* power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MIN_EXP`, then normal numbers
/// ≥&nbsp;0.5&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact minimum possible *normal* power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all normal numbers representable by this type are
/// greater than or equal to 0.5&nbsp;×&nbsp;2<sup><i>MIN_EXP</i></sup>.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MIN_EXP: i32 = -1021;
/// Maximum possible power of 2 exponent.
/// One greater than the maximum possible power of 2 exponent
/// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition).
///
/// If <i>x</i>&nbsp;=&nbsp;`MAX_EXP`, then normal numbers
/// &lt;&nbsp;1&nbsp;×&nbsp;2<sup><i>x</i></sup>.
/// This corresponds to the exact maximum possible power of 2 exponent
/// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition).
/// In other words, all numbers representable by this type are
/// strictly less than 2<sup><i>MAX_EXP</i></sup>.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MAX_EXP: i32 = 1024;

@@ -718,8 +724,7 @@ impl f64 {
pub const fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
// applies to zeros and NaNs as well.
// SAFETY: This is just transmuting to get the sign bit, it's fine.
unsafe { mem::transmute::<f64, u64>(self) & Self::SIGN_MASK != 0 }
self.to_bits() & Self::SIGN_MASK != 0
}

#[must_use]
@@ -1095,6 +1100,7 @@ impl f64 {
without modifying the original"]
#[stable(feature = "float_bits_conv", since = "1.20.0")]
#[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
#[inline]
pub const fn to_bits(self) -> u64 {
// SAFETY: `u64` is a plain old datatype so we can always transmute to it.
@@ -1141,6 +1147,7 @@ impl f64 {
#[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")]
#[must_use]
#[inline]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
pub const fn from_bits(v: u64) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u64` is a plain old datatype so we can always transmute from it.
@@ -1515,8 +1522,9 @@ impl f64 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_add(self, rhs: f64) -> f64 {
pub const fn algebraic_add(self, rhs: f64) -> f64 {
intrinsics::fadd_algebraic(self, rhs)
}

@@ -1525,8 +1533,9 @@ impl f64 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_sub(self, rhs: f64) -> f64 {
pub const fn algebraic_sub(self, rhs: f64) -> f64 {
intrinsics::fsub_algebraic(self, rhs)
}

@@ -1535,8 +1544,9 @@ impl f64 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_mul(self, rhs: f64) -> f64 {
pub const fn algebraic_mul(self, rhs: f64) -> f64 {
intrinsics::fmul_algebraic(self, rhs)
}

@@ -1545,8 +1555,9 @@ impl f64 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_div(self, rhs: f64) -> f64 {
pub const fn algebraic_div(self, rhs: f64) -> f64 {
intrinsics::fdiv_algebraic(self, rhs)
}

@@ -1555,8 +1566,9 @@ impl f64 {
/// See [algebraic operators](primitive@f32#algebraic-operators) for more info.
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "float_algebraic", issue = "136469")]
#[rustc_const_unstable(feature = "float_algebraic", issue = "136469")]
#[inline]
pub fn algebraic_rem(self, rhs: f64) -> f64 {
pub const fn algebraic_rem(self, rhs: f64) -> f64 {
intrinsics::frem_algebraic(self, rhs)
}
}
2 changes: 2 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
@@ -3675,6 +3675,7 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "int_to_from_bytes", since = "1.32.0")]
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
#[must_use = "this returns the result of the operation, \
@@ -3778,6 +3779,7 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "int_to_from_bytes", since = "1.32.0")]
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
#[must_use]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
2 changes: 2 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
@@ -3523,6 +3523,7 @@ macro_rules! uint_impl {
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
#[inline]
@@ -3624,6 +3625,7 @@ macro_rules! uint_impl {
/// ```
#[stable(feature = "int_to_from_bytes", since = "1.32.0")]
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))]
#[must_use]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
11 changes: 11 additions & 0 deletions library/std/src/sys/env_consts.rs
Original file line number Diff line number Diff line change
@@ -389,6 +389,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "exe";
}

#[cfg(target_os = "zkvm")]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".elf";
pub const DLL_EXTENSION: &str = "elf";
pub const EXE_SUFFIX: &str = ".elf";
pub const EXE_EXTENSION: &str = "elf";
}

// The fallback when none of the other gates match.
#[else]
pub mod os {
9 changes: 0 additions & 9 deletions library/std/src/sys/pal/zkvm/env.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/bootstrap/src/core/build_steps/suggest.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
let git_config = builder.config.git_config();
let suggestions = builder
.tool_cmd(Tool::SuggestTests)
.env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
.env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
.env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
.run_capture_stdout(builder)
1 change: 0 additions & 1 deletion src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
@@ -2064,7 +2064,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
}

let git_config = builder.config.git_config();
cmd.arg("--git-repository").arg(git_config.git_repository);
cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
cmd.force_coloring_in_ci();
1 change: 0 additions & 1 deletion src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
@@ -2963,7 +2963,6 @@ impl Config {

pub fn git_config(&self) -> GitConfig<'_> {
GitConfig {
git_repository: &self.stage0_metadata.config.git_repository,
nightly_branch: &self.stage0_metadata.config.nightly_branch,
git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email,
}
1 change: 0 additions & 1 deletion src/bootstrap/src/utils/tests/git.rs
Original file line number Diff line number Diff line change
@@ -135,7 +135,6 @@ impl GitCtx {

fn git_config(&self) -> GitConfig<'_> {
GitConfig {
git_repository: &self.git_repo,
nightly_branch: &self.nightly_branch,
git_merge_commit_email: &self.merge_bot_email,
}
1 change: 0 additions & 1 deletion src/build_helper/src/git.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ use crate::ci::CiEnv;

#[derive(Debug)]
pub struct GitConfig<'a> {
pub git_repository: &'a str,
pub nightly_branch: &'a str,
pub git_merge_commit_email: &'a str,
}
2 changes: 0 additions & 2 deletions src/build_helper/src/stage0_parser.rs
Original file line number Diff line number Diff line change
@@ -20,7 +20,6 @@ pub struct Stage0Config {
pub artifacts_server: String,
pub artifacts_with_llvm_assertions_server: String,
pub git_merge_commit_email: String,
pub git_repository: String,
pub nightly_branch: String,
}

@@ -49,7 +48,6 @@ pub fn parse_stage0_file() -> Stage0 {
stage0.config.artifacts_with_llvm_assertions_server = value.to_owned()
}
"git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(),
"git_repository" => stage0.config.git_repository = value.to_owned(),
"nightly_branch" => stage0.config.nightly_branch = value.to_owned(),

"compiler_date" => stage0.compiler.date = value.to_owned(),
1 change: 0 additions & 1 deletion src/stage0
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ dist_server=https://static.rust-lang.org
artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds
artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt
git_merge_commit_email=bors@rust-lang.org
git_repository=rust-lang/rust
nightly_branch=master

# The configuration above this comment is editable, and can be changed
2 changes: 0 additions & 2 deletions src/tools/bump-stage0/src/main.rs
Original file line number Diff line number Diff line change
@@ -61,7 +61,6 @@ impl Tool {
artifacts_server,
artifacts_with_llvm_assertions_server,
git_merge_commit_email,
git_repository,
nightly_branch,
} = &self.config;

@@ -72,7 +71,6 @@ impl Tool {
artifacts_with_llvm_assertions_server
));
file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email));
file_content.push_str(&format!("git_repository={}\n", git_repository));
file_content.push_str(&format!("nightly_branch={}\n", nightly_branch));

file_content.push_str("\n");
8 changes: 7 additions & 1 deletion src/tools/clippy/tests/ui/blocks_in_conditions.fixed
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//@aux-build:proc_macro_attr.rs

#![warn(clippy::blocks_in_conditions)]
#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
#![allow(
unused,
unnecessary_transmutes,
clippy::let_and_return,
clippy::needless_if,
clippy::missing_transmute_annotations
)]
#![warn(clippy::nonminimal_bool)]

macro_rules! blocky {
8 changes: 7 additions & 1 deletion src/tools/clippy/tests/ui/blocks_in_conditions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//@aux-build:proc_macro_attr.rs

#![warn(clippy::blocks_in_conditions)]
#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
#![allow(
unused,
unnecessary_transmutes,
clippy::let_and_return,
clippy::needless_if,
clippy::missing_transmute_annotations
)]
#![warn(clippy::nonminimal_bool)]

macro_rules! blocky {
6 changes: 3 additions & 3 deletions src/tools/clippy/tests/ui/blocks_in_conditions.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> tests/ui/blocks_in_conditions.rs:25:5
--> tests/ui/blocks_in_conditions.rs:31:5
|
LL | / if {
LL | |
@@ -20,13 +20,13 @@ LL ~ }; if res {
|

error: omit braces around single expression condition
--> tests/ui/blocks_in_conditions.rs:37:8
--> tests/ui/blocks_in_conditions.rs:43:8
|
LL | if { true } { 6 } else { 10 }
| ^^^^^^^^ help: try: `true`

error: this boolean expression can be simplified
--> tests/ui/blocks_in_conditions.rs:43:8
--> tests/ui/blocks_in_conditions.rs:49:8
|
LL | if true && x == 3 { 6 } else { 10 }
| ^^^^^^^^^^^^^^ help: try: `x == 3`
2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/crashes/ice-1782.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ check-pass

#![allow(dead_code, unused_variables, invalid_null_arguments)]
#![allow(dead_code, unused_variables, invalid_null_arguments, unnecessary_transmutes)]
#![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)]

/// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
1 change: 1 addition & 0 deletions src/tools/clippy/tests/ui/transmute.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
#![allow(
dead_code,
clippy::borrow_as_ptr,
unnecessary_transmutes,
clippy::needless_lifetimes,
clippy::missing_transmute_annotations
)]
108 changes: 54 additions & 54 deletions src/tools/clippy/tests/ui/transmute.stderr

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/transmute_float_to_int.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::transmute_float_to_int)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
#![feature(f128)]
#![feature(f16)]

2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/transmute_float_to_int.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::transmute_float_to_int)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
#![feature(f128)]
#![feature(f16)]

2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/transmute_int_to_char.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::transmute_int_to_char)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]

fn int_to_char() {
let _: char = unsafe { std::char::from_u32(0_u32).unwrap() };
2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/transmute_int_to_char.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::transmute_int_to_char)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]

fn int_to_char() {
let _: char = unsafe { std::mem::transmute(0_u32) };
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![no_std]
#![feature(lang_items)]
#![warn(clippy::transmute_int_to_char)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]

use core::panic::PanicInfo;

2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![no_std]
#![feature(lang_items)]
#![warn(clippy::transmute_int_to_char)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]

use core::panic::PanicInfo;

2 changes: 0 additions & 2 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
@@ -399,7 +399,6 @@ pub struct Config {
pub nocapture: bool,

// Needed both to construct build_helper::git::GitConfig
pub git_repository: String,
pub nightly_branch: String,
pub git_merge_commit_email: String,

@@ -514,7 +513,6 @@ impl Config {

pub fn git_config(&self) -> GitConfig<'_> {
GitConfig {
git_repository: &self.git_repository,
nightly_branch: &self.nightly_branch,
git_merge_commit_email: &self.git_merge_commit_email,
}
1 change: 0 additions & 1 deletion src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
@@ -175,7 +175,6 @@ impl ConfigBuilder {
self.host.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
"--target",
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
"--git-repository=",
"--nightly-branch=",
"--git-merge-commit-email=",
"--minicore-path=",
2 changes: 0 additions & 2 deletions src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -188,7 +188,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
"run tests which rely on commit version being compiled into the binaries",
)
.optopt("", "edition", "default Rust edition", "EDITION")
.reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
.reqopt(
"",
@@ -440,7 +439,6 @@ pub fn parse_config(args: Vec<String>) -> Config {

nocapture: matches.opt_present("no-capture"),

git_repository: matches.opt_str("git-repository").unwrap(),
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),

26 changes: 0 additions & 26 deletions src/tools/miri/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
@@ -391,32 +391,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}

#[rustfmt::skip]
| "fadd_algebraic"
| "fsub_algebraic"
| "fmul_algebraic"
| "fdiv_algebraic"
| "frem_algebraic"
=> {
let [a, b] = check_intrinsic_arg_count(args)?;
let a = this.read_immediate(a)?;
let b = this.read_immediate(b)?;
let op = match intrinsic_name {
"fadd_algebraic" => mir::BinOp::Add,
"fsub_algebraic" => mir::BinOp::Sub,
"fmul_algebraic" => mir::BinOp::Mul,
"fdiv_algebraic" => mir::BinOp::Div,
"frem_algebraic" => mir::BinOp::Rem,
_ => bug!(),
};
let res = this.binary_op(op, &a, &b)?;
// `binary_op` already called `generate_nan` if needed.
// Apply a relative error of 4ULP to simulate non-deterministic precision loss
// due to optimizations.
let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
this.write_immediate(*res, dest)?;
}

#[rustfmt::skip]
| "fadd_fast"
| "fsub_fast"
1 change: 1 addition & 0 deletions src/tools/miri/tests/fail/validity/invalid_bool.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unnecessary_transmutes)]
fn main() {
let _b = unsafe { std::mem::transmute::<u8, bool>(2) }; //~ ERROR: expected a boolean
}
1 change: 1 addition & 0 deletions src/tools/miri/tests/fail/validity/invalid_bool_op.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
// Make sure we find these even with many checks disabled.
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation

#![allow(unnecessary_transmutes)]
fn main() {
let b = unsafe { std::mem::transmute::<u8, bool>(2) };
let _x = b == std::hint::black_box(true); //~ ERROR: interpreting an invalid 8-bit value as a bool
1 change: 1 addition & 0 deletions src/tools/miri/tests/fail/validity/invalid_char.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unnecessary_transmutes)]
fn main() {
assert!(std::char::from_u32(-1_i32 as u32).is_none());
let _val = match unsafe { std::mem::transmute::<i32, char>(-1) } {
1 change: 1 addition & 0 deletions src/tools/miri/tests/fail/validity/invalid_char_op.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
// Make sure we find these even with many checks disabled.
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation

#![allow(unnecessary_transmutes)]
fn main() {
let c = 0xFFFFFFu32;
assert!(std::char::from_u32(c).is_none());
1 change: 1 addition & 0 deletions src/tools/miri/tests/pass/float.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
#![feature(f16)]
#![allow(arithmetic_overflow)]
#![allow(internal_features)]
#![allow(unnecessary_transmutes)]

use std::any::type_name;
use std::cmp::min;
1 change: 1 addition & 0 deletions src/tools/miri/tests/pass/issues/issue-miri-184.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unnecessary_transmutes)]
pub fn main() {
let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) };
let _val: &[u8] = &bytes;
2 changes: 1 addition & 1 deletion src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
Original file line number Diff line number Diff line change
@@ -368,7 +368,7 @@ unsafe fn load_m256i_word<T>(data: &[T], word_index: usize) -> __m256i {
#[target_feature(enable = "avx512f")]
unsafe fn load_m512i_word<T>(data: &[T], word_index: usize) -> __m512i {
let byte_offset = word_index * 64 / size_of::<T>();
let pointer = data.as_ptr().add(byte_offset) as *const i32;
let pointer = data.as_ptr().add(byte_offset) as *const __m512i;
_mm512_loadu_si512(black_box(pointer))
}

1 change: 1 addition & 0 deletions src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// We're testing x86 target specific features
//@only-target: x86_64 i686
#![allow(unnecessary_transmutes)]

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
1 change: 0 additions & 1 deletion src/tools/suggest-tests/src/main.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ use suggest_tests::get_suggestions;
fn main() -> ExitCode {
let modified_files = get_git_modified_files(
&GitConfig {
git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"),
},
45 changes: 45 additions & 0 deletions tests/codegen/autodiff/identical_fnc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
//
// Each autodiff invocation creates a new placeholder function, which we will replace on llvm-ir
// level. If a user tries to differentiate two identical functions within the same compilation unit,
// then LLVM might merge them in release mode before AD. In that case we can't rewrite one of the
// merged placeholder function anymore, and compilation would fail. We prevent this by disabling
// LLVM's merge_function pass before AD. Here we implicetely test that our solution keeps working.
// We also explicetly test that we keep running merge_function after AD, by checking for two
// identical function calls in the LLVM-IR, while having two different calls in the Rust code.
#![feature(autodiff)]

use std::autodiff::autodiff;

#[autodiff(d_square, Reverse, Duplicated, Active)]
fn square(x: &f64) -> f64 {
x * x
}

#[autodiff(d_square2, Reverse, Duplicated, Active)]
fn square2(x: &f64) -> f64 {
x * x
}

// CHECK:; identical_fnc::main
// CHECK-NEXT:; Function Attrs:
// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E()
// CHECK-NEXT:start:
// CHECK-NOT:br
// CHECK-NOT:ret
// CHECK:; call identical_fnc::d_square
// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1)
// CHECK-NEXT:; call identical_fnc::d_square
// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2)

fn main() {
let x = std::hint::black_box(3.0);
let mut dx1 = std::hint::black_box(1.0);
let mut dx2 = std::hint::black_box(1.0);
let _ = d_square(&x, &mut dx1, 1.0);
let _ = d_square2(&x, &mut dx2, 1.0);
assert_eq!(dx1, 6.0);
assert_eq!(dx2, 6.0);
}
2 changes: 1 addition & 1 deletion tests/ui/consts/const-eval/raw-bytes.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
//@ ignore-endian-big
// ignore-tidy-linelength
//@ normalize-stderr: "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼" -> "╾ALLOC_ID$1╼"
#![allow(invalid_value)]
#![allow(invalid_value, unnecessary_transmutes)]
#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]

use std::mem;
1 change: 1 addition & 0 deletions tests/ui/consts/const-eval/transmute-const-promotion.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unnecessary_transmutes)]
use std::mem;

fn main() {
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/transmute-const-promotion.rs:4:37
--> $DIR/transmute-const-promotion.rs:5:37
|
LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) };
| ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
1 change: 1 addition & 0 deletions tests/ui/consts/const-eval/transmute-const.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unnecessary_transmutes)]
use std::mem;

static FOO: bool = unsafe { mem::transmute(3u8) };
2 changes: 1 addition & 1 deletion tests/ui/consts/const-eval/transmute-const.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/transmute-const.rs:3:1
--> $DIR/transmute-const.rs:4:1
|
LL | static FOO: bool = unsafe { mem::transmute(3u8) };
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
2 changes: 1 addition & 1 deletion tests/ui/consts/const-eval/ub-enum.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
//@ normalize-stderr: "0x0+" -> "0x0"
#![feature(never_type)]
#![allow(invalid_value)]
#![allow(invalid_value, unnecessary_transmutes)]

use std::mem;

2 changes: 1 addition & 1 deletion tests/ui/consts/const-eval/ub-wide-ptr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ignore-tidy-linelength
#![allow(unused)]
#![allow(unused, unnecessary_transmutes)]
#![feature(ptr_metadata)]

use std::{ptr, mem};
1 change: 1 addition & 0 deletions tests/ui/consts/extra-const-ub/detect-extra-ub.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
//@ [no_flag] check-pass
//@ [with_flag] compile-flags: -Zextra-const-ub-checks
#![feature(never_type)]
#![allow(unnecessary_transmutes)]

use std::mem::transmute;
use std::ptr::addr_of;
16 changes: 8 additions & 8 deletions tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:29:20
--> $DIR/detect-extra-ub.rs:30:20
|
LL | let _x: bool = transmute(3u8);
| ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:35:21
--> $DIR/detect-extra-ub.rs:36:21
|
LL | let _x: usize = transmute(&3u8);
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected an integer
@@ -14,7 +14,7 @@ LL | let _x: usize = transmute(&3u8);
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:41:28
--> $DIR/detect-extra-ub.rs:42:28
|
LL | let _x: PtrSizedEnum = transmute(&3u8);
| ^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered a pointer, but expected an integer
@@ -23,7 +23,7 @@ LL | let _x: PtrSizedEnum = transmute(&3u8);
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:48:30
--> $DIR/detect-extra-ub.rs:49:30
|
LL | let _x: (usize, usize) = transmute(x);
| ^^^^^^^^^^^^ constructing invalid value at .0: encountered a pointer, but expected an integer
@@ -32,19 +32,19 @@ LL | let _x: (usize, usize) = transmute(x);
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:54:20
--> $DIR/detect-extra-ub.rs:55:20
|
LL | let _x: &u32 = transmute(&[0u8; 4]);
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:62:13
--> $DIR/detect-extra-ub.rs:63:13
|
LL | let v = *addr_of!(data).cast::<UninhDiscriminant>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:82:16
--> $DIR/detect-extra-ub.rs:83:16
|
LL | let _val = *(&mem as *const Align as *const [*const u8; 2]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a partial pointer or a mix of pointers
@@ -53,7 +53,7 @@ LL | let _val = *(&mem as *const Align as *const [*const u8; 2]);
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

error[E0080]: evaluation of constant value failed
--> $DIR/detect-extra-ub.rs:97:16
--> $DIR/detect-extra-ub.rs:98:16
|
LL | let _val = &*slice;
| ^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
4 changes: 2 additions & 2 deletions tests/ui/consts/issue-69532.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//@ run-pass

const fn make_nans() -> (f64, f64, f32, f32) {
let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) };
let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) };
let nan1 = f64::from_bits(0x7FF0_0001_0000_0001);
let nan2 = f64::from_bits(0x7FF0_0000_0000_0001);

let nan1_32 = nan1 as f32;
let nan2_32 = nan2 as f32;
1 change: 1 addition & 0 deletions tests/ui/issues/issue-25746-bool-transmute.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ run-pass
#![allow(unnecessary_transmutes)]
use std::mem::transmute;

fn main() {
12 changes: 6 additions & 6 deletions tests/ui/lint/invalid_null_args.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// check-fail
// run-rustfix
#![allow(unnecessary_transmutes)]

use std::ptr;
use std::mem;
use std::{mem, ptr};

unsafe fn null_ptr() {
ptr::write(
//~^ ERROR calling this function with a null pointer is undefined behavior
//~^ ERROR calling this function with a null pointer is undefined behavior
ptr::null_mut() as *mut u32,
mem::transmute::<[u8; 4], _>([0, 0, 0, 255]),
);

let null_ptr = ptr::null_mut();
ptr::write(
//~^ ERROR calling this function with a null pointer is undefined behavior
//~^ ERROR calling this function with a null pointer is undefined behavior
null_ptr as *mut u32,
mem::transmute::<[u8; 4], _>([0, 0, 0, 255]),
);
@@ -38,10 +38,10 @@ unsafe fn null_ptr() {
ptr::copy_nonoverlapping::<usize>(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0);
//~^ ERROR calling this function with a null pointer is undefined behavior
ptr::copy_nonoverlapping::<usize>(
//~^ ERROR calling this function with a null pointer is undefined behavior
//~^ ERROR calling this function with a null pointer is undefined behavior
ptr::NonNull::dangling().as_ptr(),
ptr::null_mut(),
0
0,
);

#[derive(Copy, Clone)]
2 changes: 1 addition & 1 deletion tests/ui/lint/invalid_null_args.stderr
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@ LL | |
LL | | ptr::NonNull::dangling().as_ptr(),
LL | | ptr::null_mut(),
| | --------------- null pointer originates from here
LL | | 0
LL | | 0,
LL | | );
| |_____^
|
18 changes: 18 additions & 0 deletions tests/ui/lint/lint-ctypes-enum.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@
#![deny(improper_ctypes)]
#![feature(ptr_internals)]
#![feature(transparent_unions)]
#![feature(repr128)]
#![allow(incomplete_features)]

use std::num;

@@ -40,6 +42,20 @@ enum Isize {
C,
}

#[repr(u128)]
enum U128 {
A,
B,
C,
}

#[repr(i128)]
enum I128 {
A,
B,
C,
}

#[repr(transparent)]
struct TransparentStruct<T>(T, std::marker::PhantomData<Z>);

@@ -71,6 +87,8 @@ extern "C" {
fn repr_c(x: ReprC);
fn repr_u8(x: U8);
fn repr_isize(x: Isize);
fn repr_u128(x: U128); //~ ERROR `extern` block uses type `U128`
fn repr_i128(x: I128); //~ ERROR `extern` block uses type `I128`
fn option_ref(x: Option<&'static u8>);
fn option_fn(x: Option<extern "C" fn()>);
fn option_nonnull(x: Option<std::ptr::NonNull<u8>>);
88 changes: 57 additions & 31 deletions tests/ui/lint/lint-ctypes-enum.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: `extern` block uses type `U`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:68:14
--> $DIR/lint-ctypes-enum.rs:84:14
|
LL | fn uf(x: U);
| ^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:9:1
--> $DIR/lint-ctypes-enum.rs:11:1
|
LL | enum U {
| ^^^^^^
@@ -18,51 +18,77 @@ LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

error: `extern` block uses type `B`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:69:14
--> $DIR/lint-ctypes-enum.rs:85:14
|
LL | fn bf(x: B);
| ^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:12:1
--> $DIR/lint-ctypes-enum.rs:14:1
|
LL | enum B {
| ^^^^^^

error: `extern` block uses type `T`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:70:14
--> $DIR/lint-ctypes-enum.rs:86:14
|
LL | fn tf(x: T);
| ^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:16:1
--> $DIR/lint-ctypes-enum.rs:18:1
|
LL | enum T {
| ^^^^^^

error: `extern` block uses type `U128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:90:21
|
LL | fn repr_u128(x: U128);
| ^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:46:1
|
LL | enum U128 {
| ^^^^^^^^^

error: `extern` block uses type `I128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:91:21
|
LL | fn repr_i128(x: I128);
| ^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:53:1
|
LL | enum I128 {
| ^^^^^^^^^

error: `extern` block uses type `u128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:82:31
--> $DIR/lint-ctypes-enum.rs:100:31
|
LL | fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:89:31
--> $DIR/lint-ctypes-enum.rs:107:31
|
LL | fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:94:36
--> $DIR/lint-ctypes-enum.rs:112:36
|
LL | fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -71,7 +97,7 @@ LL | fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>
= note: enum has no representation hint

error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:96:28
--> $DIR/lint-ctypes-enum.rs:114:28
|
LL | fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -80,7 +106,7 @@ LL | fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
= note: enum has no representation hint

error: `extern` block uses type `Option<u8>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:97:21
--> $DIR/lint-ctypes-enum.rs:115:21
|
LL | fn option_u8(x: Option<u8>);
| ^^^^^^^^^^ not FFI-safe
@@ -89,23 +115,23 @@ LL | fn option_u8(x: Option<u8>);
= note: enum has no representation hint

error: `extern` block uses type `u128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:107:33
--> $DIR/lint-ctypes-enum.rs:125:33
|
LL | fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:114:33
--> $DIR/lint-ctypes-enum.rs:132:33
|
LL | fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:119:38
--> $DIR/lint-ctypes-enum.rs:137:38
|
LL | fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -114,7 +140,7 @@ LL | fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u
= note: enum has no representation hint

error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:121:30
--> $DIR/lint-ctypes-enum.rs:139:30
|
LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -123,7 +149,7 @@ LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
= note: enum has no representation hint

error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:125:51
--> $DIR/lint-ctypes-enum.rs:143:51
|
LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -132,7 +158,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint

error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:127:53
--> $DIR/lint-ctypes-enum.rs:145:53
|
LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -141,7 +167,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
= note: enum has no representation hint

error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:129:51
--> $DIR/lint-ctypes-enum.rs:147:51
|
LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -150,7 +176,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint

error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:132:49
--> $DIR/lint-ctypes-enum.rs:150:49
|
LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -159,7 +185,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
= note: enum has no representation hint

error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:134:30
--> $DIR/lint-ctypes-enum.rs:152:30
|
LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -168,23 +194,23 @@ LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
= note: enum has no representation hint

error: `extern` block uses type `u128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:145:33
--> $DIR/lint-ctypes-enum.rs:163:33
|
LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:152:33
--> $DIR/lint-ctypes-enum.rs:170:33
|
LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:157:38
--> $DIR/lint-ctypes-enum.rs:175:38
|
LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -193,7 +219,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
= note: enum has no representation hint

error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:159:30
--> $DIR/lint-ctypes-enum.rs:177:30
|
LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -202,7 +228,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
= note: enum has no representation hint

error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:163:51
--> $DIR/lint-ctypes-enum.rs:181:51
|
LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -211,7 +237,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8
= note: enum has no representation hint

error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:165:53
--> $DIR/lint-ctypes-enum.rs:183:53
|
LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -220,7 +246,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
= note: enum has no representation hint

error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:167:51
--> $DIR/lint-ctypes-enum.rs:185:51
|
LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -229,7 +255,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
= note: enum has no representation hint

error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:170:49
--> $DIR/lint-ctypes-enum.rs:188:49
|
LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -238,7 +264,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
= note: enum has no representation hint

error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:172:30
--> $DIR/lint-ctypes-enum.rs:190:30
|
LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -247,13 +273,13 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
= note: enum has no representation hint

error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:174:27
--> $DIR/lint-ctypes-enum.rs:192:27
|
LL | fn result_unit_t_e(x: Result<(), ()>);
| ^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint

error: aborting due to 27 previous errors
error: aborting due to 29 previous errors

85 changes: 85 additions & 0 deletions tests/ui/transmute/unnecessary-transmutation.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//@ run-rustfix
#![deny(unnecessary_transmutes)]
#![allow(unused_unsafe, unused_imports, unused_variables, unused_parens)]
use std::mem::transmute;

pub fn bytes_at_home(x: u32) -> [u8; 4] {
unsafe { u32::to_ne_bytes(x) }
//~^ ERROR
}

fn main() {
unsafe {
let x: u16 = u16::from_ne_bytes(*b"01");
//~^ ERROR
let x: [u8; 2] = u16::to_ne_bytes(x);
//~^ ERROR
let x: u32 = u32::from_ne_bytes(*b"0123");
//~^ ERROR
let x: [u8; 4] = u32::to_ne_bytes(x);
//~^ ERROR
let x: u64 = u64::from_ne_bytes(*b"feriscat");
//~^ ERROR
let x: [u8; 8] = u64::to_ne_bytes(x);
//~^ ERROR

let y: i16 = i16::from_ne_bytes(*b"01");
//~^ ERROR
let y: [u8; 2] = i16::to_ne_bytes(y);
//~^ ERROR
let y: i32 = i32::from_ne_bytes(*b"0123");
//~^ ERROR
let y: [u8; 4] = i32::to_ne_bytes(y);
//~^ ERROR
let y: i64 = i64::from_ne_bytes(*b"feriscat");
//~^ ERROR
let y: [u8; 8] = i64::to_ne_bytes(y);
//~^ ERROR

let z: f32 = f32::from_ne_bytes(*b"0123");
//~^ ERROR
let z: [u8; 4] = f32::to_ne_bytes(z);
//~^ ERROR
let z: f64 = f64::from_ne_bytes(*b"feriscat");
//~^ ERROR
let z: [u8; 8] = f64::to_ne_bytes(z);
//~^ ERROR

let y: u32 = u32::from('🦀');
//~^ ERROR
let y: char = char::from_u32_unchecked(y);
//~^ ERROR

let x: u16 = i16::cast_unsigned(8i16);
//~^ ERROR
let x: i16 = u16::cast_signed(x);
//~^ ERROR
let x: u32 = i32::cast_unsigned(4i32);
//~^ ERROR
let x: i32 = u32::cast_signed(x);
//~^ ERROR
let x: u64 = i64::cast_unsigned(7i64);
//~^ ERROR
let x: i64 = u64::cast_signed(x);
//~^ ERROR

let y: f32 = f32::from_bits(1u32);
//~^ ERROR
let y: u32 = f32::to_bits(y);
//~^ ERROR
let y: f64 = f64::from_bits(3u64);
//~^ ERROR
let y: u64 = f64::to_bits(2.0);
//~^ ERROR

let z: bool = (1u8 == 1);
//~^ ERROR
let z: u8 = (z) as u8;
//~^ ERROR

let z: bool = transmute(1i8);
// no error!
let z: i8 = (z) as i8;
//~^ ERROR
}
}
85 changes: 85 additions & 0 deletions tests/ui/transmute/unnecessary-transmutation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//@ run-rustfix
#![deny(unnecessary_transmutes)]
#![allow(unused_unsafe, unused_imports, unused_variables, unused_parens)]
use std::mem::transmute;

pub fn bytes_at_home(x: u32) -> [u8; 4] {
unsafe { transmute(x) }
//~^ ERROR
}

fn main() {
unsafe {
let x: u16 = transmute(*b"01");
//~^ ERROR
let x: [u8; 2] = transmute(x);
//~^ ERROR
let x: u32 = transmute(*b"0123");
//~^ ERROR
let x: [u8; 4] = transmute(x);
//~^ ERROR
let x: u64 = transmute(*b"feriscat");
//~^ ERROR
let x: [u8; 8] = transmute(x);
//~^ ERROR

let y: i16 = transmute(*b"01");
//~^ ERROR
let y: [u8; 2] = transmute(y);
//~^ ERROR
let y: i32 = transmute(*b"0123");
//~^ ERROR
let y: [u8; 4] = transmute(y);
//~^ ERROR
let y: i64 = transmute(*b"feriscat");
//~^ ERROR
let y: [u8; 8] = transmute(y);
//~^ ERROR

let z: f32 = transmute(*b"0123");
//~^ ERROR
let z: [u8; 4] = transmute(z);
//~^ ERROR
let z: f64 = transmute(*b"feriscat");
//~^ ERROR
let z: [u8; 8] = transmute(z);
//~^ ERROR

let y: u32 = transmute('🦀');
//~^ ERROR
let y: char = transmute(y);
//~^ ERROR

let x: u16 = transmute(8i16);
//~^ ERROR
let x: i16 = transmute(x);
//~^ ERROR
let x: u32 = transmute(4i32);
//~^ ERROR
let x: i32 = transmute(x);
//~^ ERROR
let x: u64 = transmute(7i64);
//~^ ERROR
let x: i64 = transmute(x);
//~^ ERROR

let y: f32 = transmute(1u32);
//~^ ERROR
let y: u32 = transmute(y);
//~^ ERROR
let y: f64 = transmute(3u64);
//~^ ERROR
let y: u64 = transmute(2.0);
//~^ ERROR

let z: bool = transmute(1u8);
//~^ ERROR
let z: u8 = transmute(z);
//~^ ERROR

let z: bool = transmute(1i8);
// no error!
let z: i8 = transmute(z);
//~^ ERROR
}
}
235 changes: 235 additions & 0 deletions tests/ui/transmute/unnecessary-transmutation.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:7:14
|
LL | unsafe { transmute(x) }
| ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
note: the lint level is defined here
--> $DIR/unnecessary-transmutation.rs:2:9
|
LL | #![deny(unnecessary_transmutes)]
| ^^^^^^^^^^^^^^^^^^^^^^

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:13:22
|
LL | let x: u16 = transmute(*b"01");
| ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:15:26
|
LL | let x: [u8; 2] = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:17:22
|
LL | let x: u32 = transmute(*b"0123");
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:19:26
|
LL | let x: [u8; 4] = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:21:22
|
LL | let x: u64 = transmute(*b"feriscat");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:23:26
|
LL | let x: [u8; 8] = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:26:22
|
LL | let y: i16 = transmute(*b"01");
| ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:28:26
|
LL | let y: [u8; 2] = transmute(y);
| ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:30:22
|
LL | let y: i32 = transmute(*b"0123");
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:32:26
|
LL | let y: [u8; 4] = transmute(y);
| ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:34:22
|
LL | let y: i64 = transmute(*b"feriscat");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:36:26
|
LL | let y: [u8; 8] = transmute(y);
| ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:39:22
|
LL | let z: f32 = transmute(*b"0123");
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:41:26
|
LL | let z: [u8; 4] = transmute(z);
| ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:43:22
|
LL | let z: f64 = transmute(*b"feriscat");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")`
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:45:26
|
LL | let z: [u8; 8] = transmute(z);
| ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)`
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:48:22
|
LL | let y: u32 = transmute('🦀');
| ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:50:23
|
LL | let y: char = transmute(y);
| ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)`
|
= help: consider `char::from_u32(…).unwrap()`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:53:22
|
LL | let x: u16 = transmute(8i16);
| ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:55:22
|
LL | let x: i16 = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:57:22
|
LL | let x: u32 = transmute(4i32);
| ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:59:22
|
LL | let x: i32 = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:61:22
|
LL | let x: u64 = transmute(7i64);
| ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:63:22
|
LL | let x: i64 = transmute(x);
| ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:66:22
|
LL | let y: f32 = transmute(1u32);
| ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:68:22
|
LL | let y: u32 = transmute(y);
| ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:70:22
|
LL | let y: f64 = transmute(3u64);
| ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:72:22
|
LL | let y: u64 = transmute(2.0);
| ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:75:23
|
LL | let z: bool = transmute(1u8);
| ^^^^^^^^^^^^^^ help: replace this with: `(1u8 == 1)`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:77:21
|
LL | let z: u8 = transmute(z);
| ^^^^^^^^^^^^ help: replace this with: `(z) as u8`

error: unnecessary transmute
--> $DIR/unnecessary-transmutation.rs:82:21
|
LL | let z: i8 = transmute(z);
| ^^^^^^^^^^^^ help: replace this with: `(z) as i8`

error: aborting due to 32 previous errors