Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-04-25 05:01:33 +00:00
commit 65e76849ac
183 changed files with 2692 additions and 874 deletions

View file

@ -5,7 +5,7 @@ use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin};
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_span::edit_distance::find_best_match_for_name;
@ -1868,7 +1868,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
GenericParamKind::Lifetime => {
let lt_id = self.next_node_id();
let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No);
let lifetime =
self.new_named_lifetime(id, lt_id, ident, LifetimeSource::Other, ident.into());
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
lifetime,
bounds,
@ -1901,7 +1902,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
lifetime: self.lower_lifetime(lifetime),
lifetime: self.lower_lifetime(
lifetime,
LifetimeSource::Other,
lifetime.ident.into(),
),
bounds: self.lower_param_bounds(
bounds,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),

View file

@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::{
self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName,
TraitCandidate,
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource,
LifetimeSyntax, ParamName, TraitCandidate,
};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::extension;
@ -1079,7 +1079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx: ImplTraitContext,
) -> hir::GenericArg<'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(
lt,
LifetimeSource::Path { with_angle_brackets: true },
lt.ident.into(),
)),
ast::GenericArg::Type(ty) => {
// We cannot just match on `TyKind::Infer` as `(_)` is represented as
// `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
@ -1198,35 +1202,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => {
let region = region.unwrap_or_else(|| {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
{
debug_assert_eq!(start.plus(1), end);
start
} else {
self.next_node_id()
};
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
});
let lifetime = self.lower_lifetime(&region);
let lifetime = self.lower_ty_direct_lifetime(t, *region);
hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
}
TyKind::PinnedRef(region, mt) => {
let region = region.unwrap_or_else(|| {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
{
debug_assert_eq!(start.plus(1), end);
start
} else {
self.next_node_id()
};
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
});
let lifetime = self.lower_lifetime(&region);
let lifetime = self.lower_ty_direct_lifetime(t, *region);
let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx));
let span = self.lower_span(t.span);
let arg = hir::Ty { kind, span, hir_id: self.next_id() };
@ -1302,7 +1282,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime));
lifetime_bound = Some(this.lower_lifetime(
lifetime,
LifetimeSource::Other,
lifetime.ident.into(),
));
}
None
}
@ -1393,6 +1377,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
}
fn lower_ty_direct_lifetime(
&mut self,
t: &Ty,
region: Option<Lifetime>,
) -> &'hir hir::Lifetime {
let (region, syntax) = match region {
Some(region) => (region, region.ident.into()),
None => {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
{
debug_assert_eq!(start.plus(1), end);
start
} else {
self.next_node_id()
};
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id };
(region, LifetimeSyntax::Hidden)
}
};
self.lower_lifetime(&region, LifetimeSource::Reference, syntax)
}
/// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
/// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
/// HIR type that references the TAIT.
@ -1474,9 +1483,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
precise_capturing_args: &[PreciseCapturingArg],
) -> &'hir [hir::PreciseCapturingArg<'hir>] {
self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => {
hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt))
}
PreciseCapturingArg::Lifetime(lt) => hir::PreciseCapturingArg::Lifetime(
self.lower_lifetime(lt, LifetimeSource::PreciseCapturing, lt.ident.into()),
),
PreciseCapturingArg::Arg(path, id) => {
let [segment] = path.segments.as_slice() else {
panic!();
@ -1739,9 +1748,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)),
GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
}
GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime(
lifetime,
LifetimeSource::OutlivesBound,
lifetime.ident.into(),
)),
GenericBound::Use(args, span) => hir::GenericBound::Use(
self.lower_precise_capturing_args(args),
self.lower_span(*span),
@ -1749,12 +1760,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No)
fn lower_lifetime(
&mut self,
l: &Lifetime,
source: LifetimeSource,
syntax: LifetimeSyntax,
) -> &'hir hir::Lifetime {
self.new_named_lifetime(l.id, l.id, l.ident, source, syntax)
}
fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime {
self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes)
fn lower_lifetime_hidden_in_path(
&mut self,
id: NodeId,
span: Span,
with_angle_brackets: bool,
) -> &'hir hir::Lifetime {
self.new_named_lifetime(
id,
id,
Ident::new(kw::UnderscoreLifetime, span),
LifetimeSource::Path { with_angle_brackets },
LifetimeSyntax::Hidden,
)
}
#[instrument(level = "debug", skip(self))]
@ -1763,7 +1790,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
id: NodeId,
new_id: NodeId,
ident: Ident,
is_anon_in_path: IsAnonInPath,
source: LifetimeSource,
syntax: LifetimeSyntax,
) -> &'hir hir::Lifetime {
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
let res = match res {
@ -1787,17 +1815,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
};
#[cfg(debug_assertions)]
if is_anon_in_path == IsAnonInPath::Yes {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
}
debug!(?res);
self.arena.alloc(hir::Lifetime::new(
self.lower_node_id(new_id),
self.lower_ident(ident),
res,
is_anon_in_path,
source,
syntax,
))
}
@ -2389,7 +2413,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.next_id(),
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
IsAnonInPath::No,
LifetimeSource::Other,
LifetimeSyntax::Hidden,
);
debug!("elided_dyn_bound: r={:?}", r);
self.arena.alloc(r)

View file

@ -1,10 +1,9 @@
use std::sync::Arc;
use rustc_ast::{self as ast, *};
use rustc_hir as hir;
use rustc_hir::GenericArg;
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, GenericArg};
use rustc_middle::{span_bug, ty};
use rustc_session::parse::add_feature_diagnostics;
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
@ -433,23 +432,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let elided_lifetime_span = if generic_args.span.is_empty() {
let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
(segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false)
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
(generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true)
} else {
// Else use an empty span right after the opening bracket.
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
(generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true)
};
generic_args.args.insert_many(
0,
(start..end).map(|id| {
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
let l = self.lower_lifetime_hidden_in_path(
id,
elided_lifetime_span,
with_angle_brackets,
);
GenericArg::Lifetime(l)
}),
);

View file

@ -799,7 +799,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
has_bang,
Some(*ident),
macro_def.body.delim,
&macro_def.body.tokens.clone(),
&macro_def.body.tokens,
true,
sp,
);
@ -1468,7 +1468,7 @@ impl<'a> State<'a> {
true,
None,
m.args.delim,
&m.args.tokens.clone(),
&m.args.tokens,
true,
m.span(),
);

View file

@ -1,6 +1,6 @@
#![feature(no_core, unboxed_closures)]
#![no_core]
#![allow(dead_code)]
#![allow(dead_code, unnecessary_transmutes)]
extern crate mini_core;

View file

@ -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() {

View file

@ -1,5 +1,4 @@
//! Set and unset common attributes on LLVM values.
use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId;
@ -28,6 +27,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
}
}
pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool {
llvm::HasAttributeAtIndex(llfn, idx, attr)
}
pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool {
llvm::HasStringAttribute(llfn, name)
}
pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) {
llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind);
}
pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
llvm::RemoveStringAttrFromFn(llfn, name);
}
/// Get LLVM attribute for the provided inline heuristic.
#[inline]
fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {

View file

@ -28,8 +28,9 @@ use crate::back::write::{
use crate::errors::{
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
};
use crate::llvm::AttributePlace::Function;
use crate::llvm::{self, build_string};
use crate::{LlvmCodegenBackend, ModuleLlvm};
use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes};
/// We keep track of the computed LTO cache keys from the previous
/// session to determine which CGUs we can reuse.
@ -584,12 +585,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 +602,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 +652,52 @@ 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 cx =
SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
for function in cx.get_functions() {
let enzyme_marker = "enzyme_marker";
if attributes::has_string_attr(function, enzyme_marker) {
// Sanity check: Ensure 'noinline' is present before replacing it.
assert!(
!attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
"Expected __enzyme function to have 'noinline' before adding 'alwaysinline'"
);
attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline);
attributes::remove_string_attr_from_llfn(function, enzyme_marker);
assert!(
!attributes::has_string_attr(function, enzyme_marker),
"Expected function to not have 'enzyme_marker'"
);
let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx);
attributes::apply_to_llfn(function, Function, &[always_inline]);
}
}
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,

View file

@ -572,6 +572,10 @@ 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;
@ -579,13 +583,20 @@ pub(crate) unsafe fn llvm_optimize(
// 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()),

View file

@ -594,6 +594,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
unsafe {
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
llvm::LLVMSetAlignment(load, align.bytes() as c_uint);
load
}
@ -807,6 +808,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer);
unsafe {
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
let align =
if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint };
llvm::LLVMSetAlignment(store, align);

View file

@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>(
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
// We add a made-up attribute just such that we can recognize it after AD to update
// (no)-inline attributes. We'll then also remove this attribute.
let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]);
// first, remove all calls from fnc
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
let br = llvm::LLVMRustGetTerminator(entry);
@ -473,7 +478,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);

View file

@ -698,6 +698,16 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
})
}
pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
let mut functions = vec![];
let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) };
while let Some(f) = func {
functions.push(f);
func = unsafe { llvm::LLVMGetNextFunction(f) }
}
functions
}
}
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {

View file

@ -19,6 +19,19 @@ unsafe extern "C" {
pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
pub(crate) fn LLVMRustHasFnAttribute(
F: &Value,
Name: *const c_char,
NameLen: libc::size_t,
) -> bool;
pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);
pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
Fn: &Value,
index: c_uint,
kind: AttributeKind,
);
}
unsafe extern "C" {

View file

@ -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,

View file

@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
}
}
pub(crate) fn HasAttributeAtIndex<'ll>(
llfn: &'ll Value,
idx: AttributePlace,
kind: AttributeKind,
) -> bool {
unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
}
pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool {
unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
}
pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) {
unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
}
pub(crate) fn RemoveRustEnumAttributeAtIndex(
llfn: &Value,
place: AttributePlace,
kind: AttributeKind,
) {
unsafe {
LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind);
}
}
pub(crate) fn AddCallSiteAttributes<'ll>(
callsite: &'ll Value,
idx: AttributePlace,

View file

@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
(**self).borrow().llcx
}
pub(crate) fn llmod(&self) -> &'ll llvm::Module {
(**self).borrow().llmod
}
pub(crate) fn isize_ty(&self) -> &'ll Type {
(**self).borrow().isize_ty
}

View file

@ -2015,6 +2015,12 @@ fn add_linked_symbol_object(
file.set_mangling(object::write::Mangling::None);
}
if file.format() == object::BinaryFormat::MachO {
// Divide up the sections into sub-sections via symbols for dead code stripping.
// Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets.
file.set_subsections_via_symbols();
}
// ld64 requires a relocation to load undefined symbols, see below.
// Not strictly needed if linking with lld, but might as well do it there too.
let ld64_section_helper = if file.format() == object::BinaryFormat::MachO {

View file

@ -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

View file

@ -36,43 +36,110 @@ pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::{FnKind, VisitorExt};
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum IsAnonInPath {
No,
Yes,
pub enum LifetimeSource {
/// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type`
Reference,
/// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>`
Path {
/// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`,
/// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>`
/// - false for `ContainsLifetime`
with_angle_brackets: bool,
},
/// E.g. `impl Trait + '_`, `impl Trait + 'a`
OutlivesBound,
/// E.g. `impl Trait + use<'_>`, `impl Trait + use<'a>`
PreciseCapturing,
/// Other usages which have not yet been categorized. Feel free to
/// add new sources that you find useful.
///
/// Some non-exhaustive examples:
/// - `where T: 'a`
/// - `fn(_: dyn Trait + 'a)`
Other,
}
/// A lifetime. The valid field combinations are non-obvious. The following
/// example shows some of them. See also the comments on `LifetimeKind`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum LifetimeSyntax {
/// E.g. `&Type`, `ContainsLifetime`
Hidden,
/// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>`
Anonymous,
/// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>`
Named,
}
impl From<Ident> for LifetimeSyntax {
fn from(ident: Ident) -> Self {
let name = ident.name;
if name == kw::Empty {
unreachable!("A lifetime name should never be empty");
} else if name == kw::UnderscoreLifetime {
LifetimeSyntax::Anonymous
} else {
debug_assert!(name.as_str().starts_with('\''));
LifetimeSyntax::Named
}
}
}
/// A lifetime. The valid field combinations are non-obvious and not all
/// combinations are possible. The following example shows some of
/// them. See also the comments on `LifetimeKind` and `LifetimeSource`.
///
/// ```
/// #[repr(C)]
/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No
/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named
/// unsafe extern "C" {
/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes
/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No
/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden
/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named
/// }
///
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named
/// fn f() {
/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No
/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous
/// }
///
/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No
/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes
/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No
/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No
/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No
/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden
/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden
/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous
/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named
///
/// trait Tr {}
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden
///
/// fn capture_outlives<'a>() ->
/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named
/// {
/// || {}
/// }
///
/// fn capture_precise<'a>() ->
/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named
/// {
/// || {}
/// }
///
/// // (commented out because these cases trigger errors)
/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No
/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes
/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No
/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No
/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden
/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous
/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named
/// ```
///
/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
/// — there's no way to "elide" these lifetimes.
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Lifetime {
#[stable_hasher(ignore)]
@ -86,9 +153,13 @@ pub struct Lifetime {
/// Semantics of this lifetime.
pub kind: LifetimeKind,
/// Is the lifetime anonymous and in a path? Used only for error
/// suggestions. See `Lifetime::suggestion` for example use.
pub is_anon_in_path: IsAnonInPath,
/// The context in which the lifetime occurred. See `Lifetime::suggestion`
/// for example use.
pub source: LifetimeSource,
/// The syntax that the user used to declare this lifetime. See
/// `Lifetime::suggestion` for example use.
pub syntax: LifetimeSyntax,
}
#[derive(Debug, Copy, Clone, HashStable_Generic)]
@ -185,9 +256,10 @@ impl Lifetime {
hir_id: HirId,
ident: Ident,
kind: LifetimeKind,
is_anon_in_path: IsAnonInPath,
source: LifetimeSource,
syntax: LifetimeSyntax,
) -> Lifetime {
let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path };
let lifetime = Lifetime { hir_id, ident, kind, source, syntax };
// Sanity check: elided lifetimes form a strict subset of anonymous lifetimes.
#[cfg(debug_assertions)]
@ -209,23 +281,44 @@ impl Lifetime {
self.ident.name == kw::UnderscoreLifetime
}
pub fn is_syntactically_hidden(&self) -> bool {
matches!(self.syntax, LifetimeSyntax::Hidden)
}
pub fn is_syntactically_anonymous(&self) -> bool {
matches!(self.syntax, LifetimeSyntax::Anonymous)
}
pub fn is_static(&self) -> bool {
self.kind == LifetimeKind::Static
}
pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) {
use LifetimeSource::*;
use LifetimeSyntax::*;
debug_assert!(new_lifetime.starts_with('\''));
match (self.is_anon_in_path, self.ident.span.is_empty()) {
match (self.syntax, self.source) {
// The user wrote `'a` or `'_`.
(Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")),
// The user wrote `Path<T>`, and omitted the `'_,`.
(IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")),
(Hidden, Path { with_angle_brackets: true }) => {
(self.ident.span, format!("{new_lifetime}, "))
}
// The user wrote `Path` and omitted the `<'_>`.
(IsAnonInPath::Yes, false) => {
(Hidden, Path { with_angle_brackets: false }) => {
(self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>"))
}
// The user wrote `&type` or `&mut type`.
(IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")),
(Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")),
// The user wrote `'a` or `'_`.
(IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")),
(Hidden, source) => {
unreachable!("can't suggest for a hidden lifetime of {source:?}")
}
}
}
}

View file

@ -58,7 +58,8 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
hir_id: HirId::INVALID,
ident: Ident::new(sym::name, DUMMY_SP),
kind: LifetimeKind::Static,
is_anon_in_path: IsAnonInPath::No,
source: LifetimeSource::Other,
syntax: LifetimeSyntax::Hidden,
}
},
syntax,

View file

@ -759,22 +759,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Byte string patterns behave the same way as array patterns
// They can denote both statically and dynamically-sized byte arrays.
// Additionally, when `deref_patterns` is enabled, byte string literal patterns may have
// types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec<u8>`.
let mut pat_ty = ty;
if let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
} = lt.kind
{
let tcx = self.tcx;
let expected = self.structurally_resolve_type(span, expected);
if let ty::Ref(_, inner_ty, _) = *expected.kind()
&& self.try_structurally_resolve_type(span, inner_ty).is_slice()
{
let tcx = self.tcx;
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
pat_ty =
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
match *expected.kind() {
// Allow `b"...": &[u8]`
ty::Ref(_, inner_ty, _)
if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
{
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
pat_ty = Ty::new_imm_ref(
tcx,
tcx.lifetimes.re_static,
Ty::new_slice(tcx, tcx.types.u8),
);
}
// Allow `b"...": [u8; 3]` for `deref_patterns`
ty::Array(..) if tcx.features().deref_patterns() => {
pat_ty = match *ty.kind() {
ty::Ref(_, inner_ty, _) => inner_ty,
_ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
}
}
// Allow `b"...": [u8]` for `deref_patterns`
ty::Slice(..) if tcx.features().deref_patterns() => {
pat_ty = Ty::new_slice(tcx, tcx.types.u8);
}
// Otherwise, `b"...": &[u8; 3]`
_ => {}
}
}
// When `deref_patterns` is enabled, in order to allow `deref!("..."): String`, we allow
// string literal patterns to have type `str`. This is accounted for when lowering to MIR.
if self.tcx.features().deref_patterns()
&& let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
} = lt.kind
&& self.try_structurally_resolve_type(span, expected).is_str()
{
pat_ty = self.tcx.types.str_;
}
if self.tcx.features().string_deref_patterns()
&& let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..

View file

@ -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();

View file

@ -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.

View file

@ -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;)

View file

@ -973,6 +973,27 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
return nullptr;
}
extern "C" void
LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
LLVMRustAttributeKind RustAttr) {
LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
}
extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name,
size_t NameLen) {
if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
return Fn->hasFnAttribute(StringRef(Name, NameLen));
}
return false;
}
extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name,
size_t NameLen) {
if (auto *F = dyn_cast<Function>(unwrap<Value>(Fn))) {
F->removeFnAttr(StringRef(Name, NameLen));
}
}
extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
LLVMMetadataRef MD) {
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));

View file

@ -55,8 +55,7 @@ use synstructure::Structure;
///
/// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`:
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
s.underscore_const(true);
pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream {
DiagnosticDerive::new(s).into_tokens()
}
@ -102,8 +101,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
///
/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
s.underscore_const(true);
pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
LintDiagnosticDerive::new(s).into_tokens()
}
@ -153,7 +151,6 @@ pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
///
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
/// ```
pub(super) fn subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream {
s.underscore_const(true);
pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
SubdiagnosticDerive::new().into_tokens(s)
}

View file

@ -74,8 +74,6 @@ fn hash_stable_derive_with_mode(
HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
};
s.underscore_const(true);
// no_context impl is able to derive by-field, which is closer to a perfect derive.
s.add_bounds(match mode {
HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics,

View file

@ -4,7 +4,6 @@ use syn::parse_quote;
pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
s.add_bounds(synstructure::AddBounds::Generics);
s.bind_with(|_| synstructure::BindStyle::Move);
s.underscore_const(true);
let tcx: syn::Lifetime = parse_quote!('tcx);
let newtcx: syn::GenericParam = parse_quote!('__lifted);

View file

@ -12,7 +12,6 @@ pub(super) fn type_decodable_derive(
let decoder_ty = quote! { __D };
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx> });
s.add_bounds(synstructure::AddBounds::Fields);
s.underscore_const(true);
decodable_body(s, decoder_ty)
}
@ -26,7 +25,6 @@ pub(super) fn meta_decodable_derive(
s.add_impl_generic(parse_quote! { '__a });
let decoder_ty = quote! { DecodeContext<'__a, 'tcx> };
s.add_bounds(synstructure::AddBounds::Generics);
s.underscore_const(true);
decodable_body(s, decoder_ty)
}
@ -35,7 +33,6 @@ pub(super) fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro
let decoder_ty = quote! { __D };
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::SpanDecoder });
s.add_bounds(synstructure::AddBounds::Generics);
s.underscore_const(true);
decodable_body(s, decoder_ty)
}
@ -46,13 +43,12 @@ pub(super) fn decodable_nocontext_derive(
let decoder_ty = quote! { __D };
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder });
s.add_bounds(synstructure::AddBounds::Fields);
s.underscore_const(true);
decodable_body(s, decoder_ty)
}
fn decodable_body(
mut s: synstructure::Structure<'_>,
s: synstructure::Structure<'_>,
decoder_ty: TokenStream,
) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
@ -98,7 +94,6 @@ fn decodable_body(
}
}
};
s.underscore_const(true);
s.bound_impl(
quote!(::rustc_serialize::Decodable<#decoder_ty>),
@ -133,7 +128,6 @@ pub(super) fn type_encodable_derive(
}
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx> });
s.add_bounds(synstructure::AddBounds::Fields);
s.underscore_const(true);
encodable_body(s, encoder_ty, false)
}
@ -147,7 +141,6 @@ pub(super) fn meta_encodable_derive(
s.add_impl_generic(parse_quote! { '__a });
let encoder_ty = quote! { EncodeContext<'__a, 'tcx> };
s.add_bounds(synstructure::AddBounds::Generics);
s.underscore_const(true);
encodable_body(s, encoder_ty, true)
}
@ -156,7 +149,6 @@ pub(super) fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro
let encoder_ty = quote! { __E };
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder });
s.add_bounds(synstructure::AddBounds::Generics);
s.underscore_const(true);
encodable_body(s, encoder_ty, false)
}
@ -167,7 +159,6 @@ pub(super) fn encodable_nocontext_derive(
let encoder_ty = quote! { __E };
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder });
s.add_bounds(synstructure::AddBounds::Fields);
s.underscore_const(true);
encodable_body(s, encoder_ty, false)
}
@ -181,7 +172,6 @@ fn encodable_body(
panic!("cannot derive on union")
}
s.underscore_const(true);
s.bind_with(|binding| {
// Handle the lack of a blanket reference impl.
if let syn::Type::Reference(_) = binding.ast().ty {

View file

@ -6,8 +6,6 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m
panic!("cannot derive on union")
}
s.underscore_const(true);
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
s.add_impl_generic(parse_quote! { 'tcx });
}

View file

@ -8,8 +8,6 @@ pub(super) fn type_visitable_derive(
panic!("cannot derive on union")
}
s.underscore_const(true);
// ignore fields with #[type_visitable(ignore)]
s.filter(|bi| {
let mut ignored = false;

View file

@ -146,6 +146,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut place = place;
let mut block = block;
match ty.kind() {
ty::Str => {
// String literal patterns may have type `str` if `deref_patterns` is
// enabled, in order to allow `deref!("..."): String`. In this case, `value`
// is of type `&str`, so we compare it to `&place`.
if !tcx.features().deref_patterns() {
span_bug!(
test.span,
"matching on `str` went through without enabling deref_patterns"
);
}
let re_erased = tcx.lifetimes.re_erased;
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
let ref_place = self.temp(ref_str_ty, test.span);
// `let ref_place: &str = &place;`
self.cfg.push_assign(
block,
self.source_info(test.span),
ref_place,
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
);
place = ref_place;
ty = ref_str_ty;
}
ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
if !tcx.features().string_deref_patterns() {
span_bug!(

View file

@ -37,13 +37,23 @@ pub(crate) fn lit_to_const<'tcx>(
let str_bytes = s.as_str().as_bytes();
ty::ValTree::from_raw_bytes(tcx, str_bytes)
}
(ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => {
// String literal patterns may have type `str` if `deref_patterns` is enabled, in order
// to allow `deref!("..."): String`.
let str_bytes = s.as_str().as_bytes();
ty::ValTree::from_raw_bytes(tcx, str_bytes)
}
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) =>
{
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
(ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..))
if tcx.features().deref_patterns() =>
{
// Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
// enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}

View file

@ -280,6 +280,16 @@ impl<'tcx> ConstToPat<'tcx> {
slice: None,
suffix: Box::new([]),
},
ty::Str => {
// String literal patterns may have type `str` if `deref_patterns` is enabled, in
// order to allow `deref!("..."): String`. Since we need a `&str` for the comparison
// when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`.
// This works because `str` and `&str` have the same valtree representation.
let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty);
PatKind::Constant {
value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)),
}
}
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
// `&str` is represented as a valtree, let's keep using this
// optimization for now.

View file

@ -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

View file

@ -1,3 +1,4 @@
use rustc_abi::Align;
use rustc_index::IndexVec;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::PlaceContext;
@ -11,10 +12,6 @@ pub(super) struct CheckAlignment;
impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
fn is_enabled(&self, sess: &Session) -> bool {
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
if sess.target.llvm_target == "i686-pc-windows-msvc" {
return false;
}
sess.ub_checks()
}
@ -87,6 +84,33 @@ fn insert_alignment_check<'tcx>(
))),
});
// If this target does not have reliable alignment, further limit the mask by anding it with
// the mask for the highest reliable alignment.
#[allow(irrefutable_let_patterns)]
if let max_align = tcx.sess.target.max_reliable_alignment()
&& max_align < Align::MAX
{
let max_mask = max_align.bytes() - 1;
let max_mask = Operand::Constant(Box::new(ConstOperand {
span: source_info.span,
user_ty: None,
const_: Const::Val(
ConstValue::Scalar(Scalar::from_target_usize(max_mask, &tcx)),
tcx.types.usize,
),
}));
stmts.push(Statement {
source_info,
kind: StatementKind::Assign(Box::new((
alignment_mask,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(alignment_mask), max_mask)),
),
))),
});
}
// BitAnd the alignment mask with the pointer
let alignment_bits =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();

View file

@ -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);
}
}
}

View file

@ -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]

View file

@ -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),

View file

@ -1308,18 +1308,6 @@ where
return true;
}
// We don't consider a trait-bound global if it has a projection bound.
//
// See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
// for an example where this is necessary.
for p in goal.param_env.caller_bounds().iter() {
if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
return true;
}
}
}
false
}
_ => false,

View file

@ -2058,6 +2058,17 @@ impl<'a> Parser<'a> {
}
self.expect_field_ty_separator()?;
let ty = self.parse_ty()?;
if self.token == token::Colon && self.look_ahead(1, |&t| t != token::Colon) {
self.dcx()
.struct_span_err(self.token.span, "found single colon in a struct field type path")
.with_span_suggestion_verbose(
self.token.span,
"write a path separator here",
"::",
Applicability::MaybeIncorrect,
)
.emit();
}
let default = if self.token == token::Eq {
self.bump();
let const_expr = self.parse_expr_anon_const()?;

View file

@ -248,19 +248,13 @@ impl<'a> Parser<'a> {
segments.push(segment);
if self.is_import_coupler() || !self.eat_path_sep() {
let ok_for_recovery = self.may_recover()
&& match style {
PathStyle::Expr => true,
PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => {
self.token == token::Colon
&& ident.as_str().chars().all(|c| c.is_lowercase())
&& self.token.span.lo() == self.prev_token.span.hi()
&& self
.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
}
_ => false,
};
if ok_for_recovery
// IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in
// expression contexts (!) since only there paths cannot possibly be followed by
// a colon and still form a syntactically valid construct. In pattern contexts,
// a path may be followed by a type annotation. E.g., `let pat:ty`. In type
// contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`.
if self.may_recover()
&& style == PathStyle::Expr // (!)
&& self.token == token::Colon
&& self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
{

View file

@ -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,

View file

@ -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."),

View file

@ -19,7 +19,6 @@
pub mod rustc_internal;
// Make this module private for now since external users should not call these directly.
mod rustc_smir;
pub mod rustc_smir;
pub mod stable_mir;

View file

@ -18,9 +18,10 @@ use rustc_span::def_id::{CrateNum, DefId};
use scoped_tls::scoped_thread_local;
use stable_mir::Error;
use stable_mir::abi::Layout;
use stable_mir::compiler_interface::SmirInterface;
use stable_mir::ty::IndexedVal;
use crate::rustc_smir::context::TablesWrapper;
use crate::rustc_smir::context::SmirCtxt;
use crate::rustc_smir::{Stable, Tables};
use crate::stable_mir;
@ -196,12 +197,12 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
// datastructures and stable MIR datastructures
scoped_thread_local! (static TLV: Cell<*const ()>);
pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T
pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T
where
F: FnOnce() -> T,
{
assert!(!TLV.is_set());
let ptr = tables as *const _ as *const ();
let ptr = cx as *const _ as *const ();
TLV.set(&Cell::new(ptr), || f())
}
@ -212,8 +213,8 @@ pub(crate) fn with_tables<R>(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) -
TLV.with(|tlv| {
let ptr = tlv.get();
assert!(!ptr.is_null());
let wrapper = ptr as *const TablesWrapper<'_>;
let mut tables = unsafe { (*wrapper).0.borrow_mut() };
let context = ptr as *const SmirCtxt<'_>;
let mut tables = unsafe { (*context).0.borrow_mut() };
f(&mut *tables)
})
}
@ -222,7 +223,7 @@ pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
where
F: FnOnce() -> T,
{
let tables = TablesWrapper(RefCell::new(Tables {
let tables = SmirCtxt(RefCell::new(Tables {
tcx,
def_ids: IndexMap::default(),
alloc_ids: IndexMap::default(),
@ -233,7 +234,12 @@ where
mir_consts: IndexMap::default(),
layouts: IndexMap::default(),
}));
stable_mir::compiler_interface::run(&tables, || init(&tables, f))
let interface = SmirInterface { cx: tables };
// Pass the `SmirInterface` to compiler_interface::run
// and initialize the rustc-specific TLS with tables.
stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f))
}
/// Instantiate and run the compiler with the provided arguments and callback.
@ -256,7 +262,7 @@ where
/// // Your code goes in here.
/// # ControlFlow::Continue(())
/// }
/// # let args = vec!["--verbose".to_string()];
/// # let args = &["--verbose".to_string()];
/// let result = run!(args, analyze_code);
/// # assert_eq!(result, Err(CompilerError::Skipped))
/// # }
@ -278,7 +284,7 @@ where
/// // Your code goes in here.
/// # ControlFlow::Continue(())
/// }
/// # let args = vec!["--verbose".to_string()];
/// # let args = &["--verbose".to_string()];
/// # let extra_args = vec![];
/// let result = run!(args, || analyze_code(extra_args));
/// # assert_eq!(result, Err(CompilerError::Skipped))
@ -340,7 +346,6 @@ macro_rules! run_driver {
C: Send,
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
{
args: Vec<String>,
callback: Option<F>,
result: Option<ControlFlow<B, C>>,
}
@ -352,14 +357,14 @@ macro_rules! run_driver {
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
{
/// Creates a new `StableMir` instance, with given test_function and arguments.
pub fn new(args: Vec<String>, callback: F) -> Self {
StableMir { args, callback: Some(callback), result: None }
pub fn new(callback: F) -> Self {
StableMir { callback: Some(callback), result: None }
}
/// Runs the compiler against given target and tests it with `test_function`
pub fn run(&mut self) -> Result<C, CompilerError<B>> {
pub fn run(&mut self, args: &[String]) -> Result<C, CompilerError<B>> {
let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
run_compiler(&self.args.clone(), self);
run_compiler(&args, self);
Ok(())
});
match (compiler_result, self.result.take()) {
@ -409,7 +414,7 @@ macro_rules! run_driver {
}
}
StableMir::new($args, $callback).run()
StableMir::new($callback).run($args)
}};
}

View file

@ -1,7 +1,4 @@
//! Implementation of `[stable_mir::compiler_interface::Context]` trait.
//!
//! This trait is currently the main interface between the Rust compiler,
//! and the `stable_mir` crate.
//! Implementation of StableMIR Context.
#![allow(rustc::usage_of_qualified_ty)]
@ -20,7 +17,6 @@ use rustc_middle::ty::{
use rustc_middle::{mir, ty};
use rustc_span::def_id::LOCAL_CRATE;
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
use stable_mir::compiler_interface::Context;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{InstanceDef, StaticDef};
use stable_mir::mir::{BinOp, Body, Place, UnOp};
@ -37,8 +33,14 @@ use crate::rustc_smir::builder::BodyBuilder;
use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
use crate::stable_mir;
impl<'tcx> Context for TablesWrapper<'tcx> {
fn target_info(&self) -> MachineInfo {
/// Provides direct access to rustc's internal queries.
///
/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
/// this context to obtain rustc-level information.
pub struct SmirCtxt<'tcx>(pub RefCell<Tables<'tcx>>);
impl<'tcx> SmirCtxt<'tcx> {
pub fn target_info(&self) -> MachineInfo {
let mut tables = self.0.borrow_mut();
MachineInfo {
endian: tables.tcx.data_layout.endian.stable(&mut *tables),
@ -48,31 +50,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
pub fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
Some(tables.crate_item(tcx.entry_fn(())?.0))
}
fn all_local_items(&self) -> stable_mir::CrateItems {
/// Retrieve all items of the local crate that have a MIR associated with them.
pub fn all_local_items(&self) -> stable_mir::CrateItems {
let mut tables = self.0.borrow_mut();
tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
}
fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
/// Retrieve the body of a function.
/// This function will panic if the body is not available.
pub fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
let mut tables = self.0.borrow_mut();
let def_id = tables[item];
tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables)
}
fn has_body(&self, def: DefId) -> bool {
/// Check whether the body of a function is available.
pub fn has_body(&self, def: DefId) -> bool {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.internal(&mut *tables, tcx);
tables.item_has_body(def_id)
}
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
tcx.foreign_modules(crate_num.internal(&mut *tables, tcx))
@ -81,21 +87,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
/// Retrieve all functions defined in this crate.
pub fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let krate = crate_num.internal(&mut *tables, tcx);
filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
}
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
/// Retrieve all static items defined in this crate.
pub fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let krate = crate_num.internal(&mut *tables, tcx);
filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
}
fn foreign_module(
pub fn foreign_module(
&self,
mod_def: stable_mir::ty::ForeignModuleDef,
) -> stable_mir::ty::ForeignModule {
@ -105,7 +113,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
mod_def.stable(&mut *tables)
}
fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
let mut tables = self.0.borrow_mut();
let def_id = tables[mod_def.def_id()];
tables
@ -119,12 +127,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
pub fn all_trait_decls(&self) -> stable_mir::TraitDecls {
let mut tables = self.0.borrow_mut();
tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
}
fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
tcx.traits(crate_num.internal(&mut *tables, tcx))
@ -133,14 +141,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
pub fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
let mut tables = self.0.borrow_mut();
let def_id = tables[trait_def.0];
let trait_def = tables.tcx.trait_def(def_id);
trait_def.stable(&mut *tables)
}
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
iter::once(LOCAL_CRATE)
@ -150,7 +158,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx))
@ -159,21 +167,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
pub fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
let mut tables = self.0.borrow_mut();
let def_id = tables[impl_def.0];
let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
impl_trait.stable(&mut *tables)
}
fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
pub fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let generics = tables.tcx.generics_of(def_id);
generics.stable(&mut *tables)
}
fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
pub fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
@ -191,7 +199,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn explicit_predicates_of(
pub fn explicit_predicates_of(
&self,
def_id: stable_mir::DefId,
) -> stable_mir::ty::GenericPredicates {
@ -212,17 +220,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn local_crate(&self) -> stable_mir::Crate {
/// Get information about the local crate.
pub fn local_crate(&self) -> stable_mir::Crate {
let tables = self.0.borrow();
smir_crate(tables.tcx, LOCAL_CRATE)
}
fn external_crates(&self) -> Vec<stable_mir::Crate> {
/// Retrieve a list of all external crates.
pub fn external_crates(&self) -> Vec<stable_mir::Crate> {
let tables = self.0.borrow();
tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
}
fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
/// Find a crate with the given name.
pub fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
let tables = self.0.borrow();
let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
.iter()
@ -235,7 +246,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
crates
}
fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
/// Returns the name of given `DefId`.
pub fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
let tables = self.0.borrow();
if trimmed {
with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
@ -244,7 +256,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn tool_attrs(
/// Return registered tool attributes with the given attribute name.
///
/// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
/// attributes will simply return an empty list.
///
/// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
pub fn tool_attrs(
&self,
def_id: stable_mir::DefId,
attr: &[stable_mir::Symbol],
@ -268,7 +287,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> {
/// Get all tool attributes of a definition.
pub fn all_tool_attrs(
&self,
def_id: stable_mir::DefId,
) -> Vec<stable_mir::crate_def::Attribute> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let did = tables[def_id];
@ -292,12 +315,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.collect()
}
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
/// Returns printable, human readable form of `Span`.
pub fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
let tables = self.0.borrow();
tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
}
fn get_filename(&self, span: &Span) -> Filename {
/// Return filename from given `Span`, for diagnostic purposes.
pub fn get_filename(&self, span: &Span) -> Filename {
let tables = self.0.borrow();
tables
.tcx
@ -308,23 +333,27 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.to_string()
}
fn get_lines(&self, span: &Span) -> LineInfo {
/// Return lines corresponding to this `Span`.
pub fn get_lines(&self, span: &Span) -> LineInfo {
let tables = self.0.borrow();
let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
}
fn item_kind(&self, item: CrateItem) -> ItemKind {
/// Returns the `kind` of given `DefId`.
pub fn item_kind(&self, item: CrateItem) -> ItemKind {
let tables = self.0.borrow();
new_item_kind(tables.tcx.def_kind(tables[item.0]))
}
fn is_foreign_item(&self, item: DefId) -> bool {
/// Returns whether this is a foreign item.
pub fn is_foreign_item(&self, item: DefId) -> bool {
let tables = self.0.borrow();
tables.tcx.is_foreign_item(tables[item])
}
fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
/// Returns the kind of a given foreign item.
pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
let mut tables = self.0.borrow_mut();
let def_id = tables[def.def_id()];
let tcx = tables.tcx;
@ -339,32 +368,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn adt_kind(&self, def: AdtDef) -> AdtKind {
/// Returns the kind of a given algebraic data type.
pub fn adt_kind(&self, def: AdtDef) -> AdtKind {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables)
}
fn adt_is_box(&self, def: AdtDef) -> bool {
/// Returns if the ADT is a box.
pub fn adt_is_box(&self, def: AdtDef) -> bool {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).is_box()
}
fn adt_is_simd(&self, def: AdtDef) -> bool {
/// Returns whether this ADT is simd.
pub fn adt_is_simd(&self, def: AdtDef) -> bool {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).repr().simd()
}
fn adt_is_cstr(&self, def: AdtDef) -> bool {
/// Returns whether this definition is a C string.
pub fn adt_is_cstr(&self, def: AdtDef) -> bool {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.0.internal(&mut *tables, tcx);
tables.tcx.is_lang_item(def_id, LangItem::CStr)
}
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
/// Retrieve the function signature for the given generic arguments.
pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.0.internal(&mut *tables, tcx);
@ -373,7 +407,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
sig.stable(&mut *tables)
}
fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
/// Retrieve the intrinsic definition if the item corresponds one.
pub fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.internal(&mut *tables, tcx);
@ -381,14 +416,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
intrinsic.map(|_| IntrinsicDef(def))
}
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
/// Retrieve the plain function name of an intrinsic.
pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.0.internal(&mut *tables, tcx);
tcx.intrinsic(def_id).unwrap().name.to_string()
}
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
/// Retrieve the closure signature for the given generic arguments.
pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let args_ref = args.internal(&mut *tables, tcx);
@ -396,25 +433,28 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
sig.stable(&mut *tables)
}
fn adt_variants_len(&self, def: AdtDef) -> usize {
/// The number of variants in this ADT.
pub fn adt_variants_len(&self, def: AdtDef) -> usize {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).variants().len()
}
fn variant_name(&self, def: VariantDef) -> Symbol {
/// The name of a variant.
pub fn variant_name(&self, def: VariantDef) -> Symbol {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).name.to_string()
}
fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
pub fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect()
}
fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
/// Evaluate constant as a target usize.
pub fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let mir_const = cnst.internal(&mut *tables, tcx);
@ -422,7 +462,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized())
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
}
fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let mir_const = cnst.internal(&mut *tables, tcx);
@ -431,7 +471,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
}
fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
/// Create a new zero-sized constant.
pub fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let ty_internal = ty.internal(&mut *tables, tcx);
@ -456,7 +497,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.stable(&mut *tables))
}
fn new_const_str(&self, value: &str) -> MirConst {
/// Create a new constant that represents the given string value.
pub fn new_const_str(&self, value: &str) -> MirConst {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let ty = ty::Ty::new_static_str(tcx);
@ -467,12 +509,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
mir::Const::from_value(val, ty).stable(&mut tables)
}
fn new_const_bool(&self, value: bool) -> MirConst {
/// Create a new constant that represents the given boolean value.
pub fn new_const_bool(&self, value: bool) -> MirConst {
let mut tables = self.0.borrow_mut();
mir::Const::from_bool(tables.tcx, value).stable(&mut tables)
}
fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
/// Create a new constant that represents the given value.
pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
@ -487,7 +531,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty)
.stable(&mut tables))
}
fn try_new_ty_const_uint(
pub fn try_new_ty_const_uint(
&self,
value: u128,
uint_ty: UintTy,
@ -509,27 +553,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.stable(&mut *tables))
}
fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
/// Create a new type from the given kind.
pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let internal_kind = kind.internal(&mut *tables, tcx);
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
}
fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
/// Create a new box type, `Box<T>`, for the given inner type `T`.
pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let inner = ty.internal(&mut *tables, tcx);
ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables)
}
fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
/// Returns the type of given crate item.
pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables)
}
fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty {
/// Returns the type of given definition instantiated with the given arguments.
pub fn def_ty_with_args(
&self,
item: stable_mir::DefId,
args: &GenericArgs,
) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let args = args.internal(&mut *tables, tcx);
@ -544,33 +596,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.stable(&mut *tables)
}
fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
/// Returns literal value of a const as a string.
pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
cnst.internal(&mut *tables, tcx).to_string()
}
fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
/// `Span` of an item.
pub fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
let mut tables = self.0.borrow_mut();
tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
}
fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
/// Obtain the representation of a type.
pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
let tables = self.0.borrow_mut();
tables.types[ty].to_string()
}
fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
/// Obtain the representation of a type.
pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
let mut tables = self.0.borrow_mut();
tables.types[ty].kind().stable(&mut *tables)
}
fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
let tables = self.0.borrow_mut();
tables.ty_consts[ct].to_string()
}
fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
/// Get the discriminant Ty for this Ty if there's one.
pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let internal_kind = ty.internal(&mut *tables, tcx);
@ -578,7 +635,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables)
}
fn instance_body(&self, def: InstanceDef) -> Option<Body> {
/// Get the body of an Instance which is already monomorphized.
pub fn instance_body(&self, def: InstanceDef) -> Option<Body> {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
tables
@ -586,63 +644,74 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
}
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
/// Get the instance type with generic instantiations applied and lifetimes erased.
pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables)
}
fn instance_args(&self, def: InstanceDef) -> GenericArgs {
/// Get the instantiation types.
pub fn instance_args(&self, def: InstanceDef) -> GenericArgs {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
instance.args.stable(&mut *tables)
}
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
/// Get an instance ABI.
pub fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
}
fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
/// Get the ABI of a function pointer.
pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let sig = fn_ptr.internal(&mut *tables, tcx);
Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables))
}
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
/// Get the instance.
pub fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
let mut tables = self.0.borrow_mut();
let def_id = tables.instances[def].def_id();
tables.create_def_id(def_id)
}
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
/// Get the instance mangled name.
pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
let tables = self.0.borrow_mut();
let instance = tables.instances[instance];
tables.tcx.symbol_name(instance).name.to_string()
}
fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
/// Check if this is an empty DropGlue shim.
pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
let tables = self.0.borrow_mut();
let instance = tables.instances[def];
matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
}
fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
/// Check if this is an empty AsyncDropGlueCtor shim.
pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
let tables = self.0.borrow_mut();
let instance = tables.instances[def];
matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None))
}
fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
/// Convert a non-generic crate item into an instance.
/// This function will panic if the item is generic.
pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
Instance::mono(tables.tcx, def_id).stable(&mut *tables)
}
fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
/// Item requires monomorphization.
pub fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
let tables = self.0.borrow();
let def_id = tables[def_id];
let generics = tables.tcx.generics_of(def_id);
@ -650,7 +719,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
result
}
fn resolve_instance(
/// Resolve an instance from the given function definition and generic arguments.
pub fn resolve_instance(
&self,
def: stable_mir::ty::FnDef,
args: &stable_mir::ty::GenericArgs,
@ -670,7 +740,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
/// Resolve an instance for drop_in_place for the given type.
pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let internal_ty = ty.internal(&mut *tables, tcx);
@ -678,7 +749,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
instance.stable(&mut *tables)
}
fn resolve_for_fn_ptr(
/// Resolve instance for a function pointer.
pub fn resolve_for_fn_ptr(
&self,
def: FnDef,
args: &GenericArgs,
@ -696,7 +768,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.stable(&mut *tables)
}
fn resolve_closure(
/// Resolve instance for a closure with the requested type.
pub fn resolve_closure(
&self,
def: ClosureDef,
args: &GenericArgs,
@ -713,7 +786,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
)
}
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
/// Try to evaluate an instance into a constant.
pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
let tcx = tables.tcx;
@ -733,21 +807,24 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
.map_err(|e| e.stable(&mut *tables))?
}
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
/// Evaluate a static's initializer.
pub fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = def.0.internal(&mut *tables, tcx);
tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
}
fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
/// Retrieve global allocation for the given allocation ID.
pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let alloc_id = alloc.internal(&mut *tables, tcx);
tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
}
fn vtable_allocation(
/// Retrieve the id for the virtual table.
pub fn vtable_allocation(
&self,
global_alloc: &GlobalAlloc,
) -> Option<stable_mir::mir::alloc::AllocId> {
@ -765,7 +842,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
Some(alloc_id.stable(&mut *tables))
}
fn krate(&self, def_id: stable_mir::DefId) -> Crate {
pub fn krate(&self, def_id: stable_mir::DefId) -> Crate {
let tables = self.0.borrow();
smir_crate(tables.tcx, tables[def_id].krate)
}
@ -773,7 +850,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
/// Retrieve the instance name for diagnostic messages.
///
/// This will return the specialized name, e.g., `Vec<char>::new`.
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
let tables = self.0.borrow_mut();
let instance = tables.instances[def];
if trimmed {
@ -787,7 +864,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
/// Get the layout of a type.
pub fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let ty = ty.internal(&mut *tables, tcx);
@ -795,19 +873,22 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
Ok(layout.stable(&mut *tables))
}
fn layout_shape(&self, id: Layout) -> LayoutShape {
/// Get the layout shape.
pub fn layout_shape(&self, id: Layout) -> LayoutShape {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
id.internal(&mut *tables, tcx).0.stable(&mut *tables)
}
fn place_pretty(&self, place: &Place) -> String {
/// Get a debug string representation of a place.
pub fn place_pretty(&self, place: &Place) -> String {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
format!("{:?}", place.internal(&mut *tables, tcx))
}
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
/// Get the resulting type of binary operation.
pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let rhs_internal = rhs.internal(&mut *tables, tcx);
@ -816,7 +897,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
ty.stable(&mut *tables)
}
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
/// Get the resulting type of unary operation.
pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let arg_internal = arg.internal(&mut *tables, tcx);
@ -824,7 +906,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
ty.stable(&mut *tables)
}
fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
/// Get all associated items of a definition.
pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
let def_id = tables[def_id];
@ -840,8 +923,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
}
pub(crate) struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
/// Implement error handling for extracting function ABI information.
impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;

View file

@ -25,7 +25,7 @@ use crate::stable_mir;
mod alloc;
mod builder;
pub(crate) mod context;
pub mod context;
mod convert;
pub struct Tables<'tcx> {

View file

@ -5,6 +5,7 @@
use std::cell::Cell;
use rustc_smir::context::SmirCtxt;
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
use stable_mir::crate_def::Attribute;
use stable_mir::mir::alloc::{AllocId, GlobalAlloc};
@ -22,47 +23,116 @@ use stable_mir::{
ItemKind, Symbol, TraitDecls, mir,
};
use crate::stable_mir;
use crate::{rustc_smir, stable_mir};
/// Stable public API for querying compiler information.
///
/// All queries are delegated to an internal [`SmirCtxt`] that provides
/// similar APIs but based on internal rustc constructs.
///
/// Do not use this directly. This is currently used in the macro expansion.
pub(crate) struct SmirInterface<'tcx> {
pub(crate) cx: SmirCtxt<'tcx>,
}
impl<'tcx> SmirInterface<'tcx> {
pub(crate) fn entry_fn(&self) -> Option<CrateItem> {
self.cx.entry_fn()
}
/// This trait defines the interface between stable_mir and the Rust compiler.
/// Do not use this directly.
pub trait Context {
fn entry_fn(&self) -> Option<CrateItem>;
/// Retrieve all items of the local crate that have a MIR associated with them.
fn all_local_items(&self) -> CrateItems;
pub(crate) fn all_local_items(&self) -> CrateItems {
self.cx.all_local_items()
}
/// Retrieve the body of a function.
/// This function will panic if the body is not available.
fn mir_body(&self, item: DefId) -> mir::Body;
pub(crate) fn mir_body(&self, item: DefId) -> mir::Body {
self.cx.mir_body(item)
}
/// Check whether the body of a function is available.
fn has_body(&self, item: DefId) -> bool;
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
pub(crate) fn has_body(&self, item: DefId) -> bool {
self.cx.has_body(item)
}
pub(crate) fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef> {
self.cx.foreign_modules(crate_num)
}
/// Retrieve all functions defined in this crate.
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>;
pub(crate) fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
self.cx.crate_functions(crate_num)
}
/// Retrieve all static items defined in this crate.
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>;
fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
fn all_trait_decls(&self) -> TraitDecls;
fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
fn all_trait_impls(&self) -> ImplTraitDecls;
fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
fn generics_of(&self, def_id: DefId) -> Generics;
fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
pub(crate) fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
self.cx.crate_statics(crate_num)
}
pub(crate) fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule {
self.cx.foreign_module(mod_def)
}
pub(crate) fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef> {
self.cx.foreign_items(mod_def)
}
pub(crate) fn all_trait_decls(&self) -> TraitDecls {
self.cx.all_trait_decls()
}
pub(crate) fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls {
self.cx.trait_decls(crate_num)
}
pub(crate) fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl {
self.cx.trait_decl(trait_def)
}
pub(crate) fn all_trait_impls(&self) -> ImplTraitDecls {
self.cx.all_trait_impls()
}
pub(crate) fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls {
self.cx.trait_impls(crate_num)
}
pub(crate) fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait {
self.cx.trait_impl(trait_impl)
}
pub(crate) fn generics_of(&self, def_id: DefId) -> Generics {
self.cx.generics_of(def_id)
}
pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates {
self.cx.predicates_of(def_id)
}
pub(crate) fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates {
self.cx.explicit_predicates_of(def_id)
}
/// Get information about the local crate.
fn local_crate(&self) -> Crate;
pub(crate) fn local_crate(&self) -> Crate {
self.cx.local_crate()
}
/// Retrieve a list of all external crates.
fn external_crates(&self) -> Vec<Crate>;
pub(crate) fn external_crates(&self) -> Vec<Crate> {
self.cx.external_crates()
}
/// Find a crate with the given name.
fn find_crates(&self, name: &str) -> Vec<Crate>;
pub(crate) fn find_crates(&self, name: &str) -> Vec<Crate> {
self.cx.find_crates(name)
}
/// Returns the name of given `DefId`
fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
/// Returns the name of given `DefId`.
pub(crate) fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol {
self.cx.def_name(def_id, trimmed)
}
/// Return registered tool attributes with the given attribute name.
///
@ -71,218 +141,362 @@ pub trait Context {
///
/// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
pub(crate) fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute> {
self.cx.tool_attrs(def_id, attr)
}
/// Get all tool attributes of a definition.
fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute>;
pub(crate) fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute> {
self.cx.all_tool_attrs(def_id)
}
/// Returns printable, human readable form of `Span`
fn span_to_string(&self, span: Span) -> String;
/// Returns printable, human readable form of `Span`.
pub(crate) fn span_to_string(&self, span: Span) -> String {
self.cx.span_to_string(span)
}
/// Return filename from given `Span`, for diagnostic purposes
fn get_filename(&self, span: &Span) -> Filename;
/// Return filename from given `Span`, for diagnostic purposes.
pub(crate) fn get_filename(&self, span: &Span) -> Filename {
self.cx.get_filename(span)
}
/// Return lines corresponding to this `Span`
fn get_lines(&self, span: &Span) -> LineInfo;
/// Return lines corresponding to this `Span`.
pub(crate) fn get_lines(&self, span: &Span) -> LineInfo {
self.cx.get_lines(span)
}
/// Returns the `kind` of given `DefId`
fn item_kind(&self, item: CrateItem) -> ItemKind;
/// Returns the `kind` of given `DefId`.
pub(crate) fn item_kind(&self, item: CrateItem) -> ItemKind {
self.cx.item_kind(item)
}
/// Returns whether this is a foreign item.
fn is_foreign_item(&self, item: DefId) -> bool;
pub(crate) fn is_foreign_item(&self, item: DefId) -> bool {
self.cx.is_foreign_item(item)
}
/// Returns the kind of a given foreign item.
fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind;
pub(crate) fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
self.cx.foreign_item_kind(def)
}
/// Returns the kind of a given algebraic data type
fn adt_kind(&self, def: AdtDef) -> AdtKind;
/// Returns the kind of a given algebraic data type.
pub(crate) fn adt_kind(&self, def: AdtDef) -> AdtKind {
self.cx.adt_kind(def)
}
/// Returns if the ADT is a box.
fn adt_is_box(&self, def: AdtDef) -> bool;
pub(crate) fn adt_is_box(&self, def: AdtDef) -> bool {
self.cx.adt_is_box(def)
}
/// Returns whether this ADT is simd.
fn adt_is_simd(&self, def: AdtDef) -> bool;
pub(crate) fn adt_is_simd(&self, def: AdtDef) -> bool {
self.cx.adt_is_simd(def)
}
/// Returns whether this definition is a C string.
fn adt_is_cstr(&self, def: AdtDef) -> bool;
pub(crate) fn adt_is_cstr(&self, def: AdtDef) -> bool {
self.cx.adt_is_cstr(def)
}
/// Retrieve the function signature for the given generic arguments.
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
self.cx.fn_sig(def, args)
}
/// Retrieve the intrinsic definition if the item corresponds one.
fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>;
pub(crate) fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef> {
self.cx.intrinsic(item)
}
/// Retrieve the plain function name of an intrinsic.
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
pub(crate) fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
self.cx.intrinsic_name(def)
}
/// Retrieve the closure signature for the given generic arguments.
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
pub(crate) fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
self.cx.closure_sig(args)
}
/// The number of variants in this ADT.
fn adt_variants_len(&self, def: AdtDef) -> usize;
pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize {
self.cx.adt_variants_len(def)
}
/// The name of a variant.
fn variant_name(&self, def: VariantDef) -> Symbol;
fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>;
pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol {
self.cx.variant_name(def)
}
pub(crate) fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
self.cx.variant_fields(def)
}
/// Evaluate constant as a target usize.
fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error>;
fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error>;
pub(crate) fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
self.cx.eval_target_usize(cnst)
}
pub(crate) fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
self.cx.eval_target_usize_ty(cnst)
}
/// Create a new zero-sized constant.
fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error>;
pub(crate) fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
self.cx.try_new_const_zst(ty)
}
/// Create a new constant that represents the given string value.
fn new_const_str(&self, value: &str) -> MirConst;
pub(crate) fn new_const_str(&self, value: &str) -> MirConst {
self.cx.new_const_str(value)
}
/// Create a new constant that represents the given boolean value.
fn new_const_bool(&self, value: bool) -> MirConst;
pub(crate) fn new_const_bool(&self, value: bool) -> MirConst {
self.cx.new_const_bool(value)
}
/// Create a new constant that represents the given value.
fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error>;
fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error>;
pub(crate) fn try_new_const_uint(
&self,
value: u128,
uint_ty: UintTy,
) -> Result<MirConst, Error> {
self.cx.try_new_const_uint(value, uint_ty)
}
pub(crate) fn try_new_ty_const_uint(
&self,
value: u128,
uint_ty: UintTy,
) -> Result<TyConst, Error> {
self.cx.try_new_ty_const_uint(value, uint_ty)
}
/// Create a new type from the given kind.
fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
pub(crate) fn new_rigid_ty(&self, kind: RigidTy) -> Ty {
self.cx.new_rigid_ty(kind)
}
/// Create a new box type, `Box<T>`, for the given inner type `T`.
fn new_box_ty(&self, ty: Ty) -> Ty;
pub(crate) fn new_box_ty(&self, ty: Ty) -> Ty {
self.cx.new_box_ty(ty)
}
/// Returns the type of given crate item.
fn def_ty(&self, item: DefId) -> Ty;
pub(crate) fn def_ty(&self, item: DefId) -> Ty {
self.cx.def_ty(item)
}
/// Returns the type of given definition instantiated with the given arguments.
fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
pub(crate) fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty {
self.cx.def_ty_with_args(item, args)
}
/// Returns literal value of a const as a string.
fn mir_const_pretty(&self, cnst: &MirConst) -> String;
pub(crate) fn mir_const_pretty(&self, cnst: &MirConst) -> String {
self.cx.mir_const_pretty(cnst)
}
/// `Span` of an item
fn span_of_an_item(&self, def_id: DefId) -> Span;
/// `Span` of an item.
pub(crate) fn span_of_an_item(&self, def_id: DefId) -> Span {
self.cx.span_of_an_item(def_id)
}
fn ty_const_pretty(&self, ct: TyConstId) -> String;
pub(crate) fn ty_const_pretty(&self, ct: TyConstId) -> String {
self.cx.ty_const_pretty(ct)
}
/// Obtain the representation of a type.
fn ty_pretty(&self, ty: Ty) -> String;
pub(crate) fn ty_pretty(&self, ty: Ty) -> String {
self.cx.ty_pretty(ty)
}
/// Obtain the representation of a type.
fn ty_kind(&self, ty: Ty) -> TyKind;
pub(crate) fn ty_kind(&self, ty: Ty) -> TyKind {
self.cx.ty_kind(ty)
}
// Get the discriminant Ty for this Ty if there's one.
fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty;
/// Get the discriminant Ty for this Ty if there's one.
pub(crate) fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty {
self.cx.rigid_ty_discriminant_ty(ty)
}
/// Get the body of an Instance which is already monomorphized.
fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
pub(crate) fn instance_body(&self, instance: InstanceDef) -> Option<Body> {
self.cx.instance_body(instance)
}
/// Get the instance type with generic instantiations applied and lifetimes erased.
fn instance_ty(&self, instance: InstanceDef) -> Ty;
pub(crate) fn instance_ty(&self, instance: InstanceDef) -> Ty {
self.cx.instance_ty(instance)
}
/// Get the instantiation types.
fn instance_args(&self, def: InstanceDef) -> GenericArgs;
pub(crate) fn instance_args(&self, def: InstanceDef) -> GenericArgs {
self.cx.instance_args(def)
}
/// Get the instance.
fn instance_def_id(&self, instance: InstanceDef) -> DefId;
pub(crate) fn instance_def_id(&self, instance: InstanceDef) -> DefId {
self.cx.instance_def_id(instance)
}
/// Get the instance mangled name.
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
pub(crate) fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
self.cx.instance_mangled_name(instance)
}
/// Check if this is an empty DropGlue shim.
fn is_empty_drop_shim(&self, def: InstanceDef) -> bool;
pub(crate) fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
self.cx.is_empty_drop_shim(def)
}
/// Check if this is an empty AsyncDropGlueCtor shim.
fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool;
pub(crate) fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
self.cx.is_empty_async_drop_ctor_shim(def)
}
/// Convert a non-generic crate item into an instance.
/// This function will panic if the item is generic.
fn mono_instance(&self, def_id: DefId) -> Instance;
pub(crate) fn mono_instance(&self, def_id: DefId) -> Instance {
self.cx.mono_instance(def_id)
}
/// Item requires monomorphization.
fn requires_monomorphization(&self, def_id: DefId) -> bool;
pub(crate) fn requires_monomorphization(&self, def_id: DefId) -> bool {
self.cx.requires_monomorphization(def_id)
}
/// Resolve an instance from the given function definition and generic arguments.
fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
pub(crate) fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
self.cx.resolve_instance(def, args)
}
/// Resolve an instance for drop_in_place for the given type.
fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
pub(crate) fn resolve_drop_in_place(&self, ty: Ty) -> Instance {
self.cx.resolve_drop_in_place(ty)
}
/// Resolve instance for a function pointer.
fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
pub(crate) fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
self.cx.resolve_for_fn_ptr(def, args)
}
/// Resolve instance for a closure with the requested type.
fn resolve_closure(
pub(crate) fn resolve_closure(
&self,
def: ClosureDef,
args: &GenericArgs,
kind: ClosureKind,
) -> Option<Instance>;
) -> Option<Instance> {
self.cx.resolve_closure(def, args, kind)
}
/// Evaluate a static's initializer.
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
pub(crate) fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
self.cx.eval_static_initializer(def)
}
/// Try to evaluate an instance into a constant.
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;
pub(crate) fn eval_instance(
&self,
def: InstanceDef,
const_ty: Ty,
) -> Result<Allocation, Error> {
self.cx.eval_instance(def, const_ty)
}
/// Retrieve global allocation for the given allocation ID.
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
pub(crate) fn global_alloc(&self, id: AllocId) -> GlobalAlloc {
self.cx.global_alloc(id)
}
/// Retrieve the id for the virtual table.
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
fn krate(&self, def_id: DefId) -> Crate;
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
pub(crate) fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId> {
self.cx.vtable_allocation(global_alloc)
}
pub(crate) fn krate(&self, def_id: DefId) -> Crate {
self.cx.krate(def_id)
}
pub(crate) fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
self.cx.instance_name(def, trimmed)
}
/// Return information about the target machine.
fn target_info(&self) -> MachineInfo;
pub(crate) fn target_info(&self) -> MachineInfo {
self.cx.target_info()
}
/// Get an instance ABI.
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
pub(crate) fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
self.cx.instance_abi(def)
}
/// Get the ABI of a function pointer.
fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error>;
pub(crate) fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
self.cx.fn_ptr_abi(fn_ptr)
}
/// Get the layout of a type.
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
pub(crate) fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
self.cx.ty_layout(ty)
}
/// Get the layout shape.
fn layout_shape(&self, id: Layout) -> LayoutShape;
pub(crate) fn layout_shape(&self, id: Layout) -> LayoutShape {
self.cx.layout_shape(id)
}
/// Get a debug string representation of a place.
fn place_pretty(&self, place: &Place) -> String;
pub(crate) fn place_pretty(&self, place: &Place) -> String {
self.cx.place_pretty(place)
}
/// Get the resulting type of binary operation.
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
pub(crate) fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
self.cx.binop_ty(bin_op, rhs, lhs)
}
/// Get the resulting type of unary operation.
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty;
pub(crate) fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
self.cx.unop_ty(un_op, arg)
}
/// Get all associated items of a definition.
fn associated_items(&self, def_id: DefId) -> AssocItems;
pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
self.cx.associated_items(def_id)
}
}
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
// datastructures and stable MIR datastructures
// A thread local variable that stores a pointer to [`SmirInterface`].
scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>);
pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
pub(crate) fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result<T, Error>
where
F: FnOnce() -> T,
{
if TLV.is_set() {
Err(Error::from("StableMIR already running"))
} else {
let ptr: *const () = (&raw const context) as _;
let ptr: *const () = (interface as *const SmirInterface<'tcx>) as *const ();
TLV.set(&Cell::new(ptr), || Ok(f()))
}
}
/// Execute the given function with access the compiler [Context].
/// Execute the given function with access the [`SmirInterface`].
///
/// I.e., This function will load the current context and calls a function with it.
/// I.e., This function will load the current interface and calls a function with it.
/// Do not nest these, as that will ICE.
pub(crate) fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
pub(crate) fn with<R>(f: impl FnOnce(&SmirInterface<'_>) -> R) -> R {
assert!(TLV.is_set());
TLV.with(|tlv| {
let ptr = tlv.get();
assert!(!ptr.is_null());
f(unsafe { *(ptr as *const &dyn Context) })
f(unsafe { &*(ptr as *const SmirInterface<'_>) })
})
}

View file

@ -144,6 +144,7 @@ pub struct ArgAttributes {
/// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be
/// set on a null pointer, but all non-null pointers must be dereferenceable).
pub pointee_size: Size,
/// The minimum alignment of the pointee, if any.
pub pointee_align: Option<Align>,
}

View file

@ -42,7 +42,9 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{fmt, io};
use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
use rustc_abi::{
Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_fs_util::try_canonicalize;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
@ -3599,6 +3601,25 @@ impl Target {
_ => return None,
})
}
/// Returns whether this target is known to have unreliable alignment:
/// native C code for the target fails to align some data to the degree
/// required by the C standard. We can't *really* do anything about that
/// since unsafe Rust code may assume alignment any time, but we can at least
/// inhibit some optimizations, and we suppress the alignment checks that
/// would detect this unsoundness.
///
/// Every target that returns less than `Align::MAX` here is still has a soundness bug.
pub fn max_reliable_alignment(&self) -> Align {
// FIXME(#112480) MSVC on x86-32 is unsound and fails to properly align many types with
// more-than-4-byte-alignment on the stack. This makes alignments larger than 4 generally
// unreliable on 32bit Windows.
if self.is_like_windows && self.arch == "x86" {
Align::from_bytes(4).unwrap()
} else {
Align::MAX
}
}
}
/// Either a target tuple string or a path to a JSON file.

View file

@ -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"]),

View file

@ -9,7 +9,7 @@ use rustc_errors::{
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node};
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt};
@ -551,19 +551,6 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
let make_suggestion = |lifetime: &hir::Lifetime| {
if lifetime.is_anon_in_path == IsAnonInPath::Yes
&& lifetime.ident.span.is_empty()
{
format!("{}, ", self.suggestion_param_name)
} else if lifetime.ident.name == kw::UnderscoreLifetime
&& lifetime.ident.span.is_empty()
{
format!("{} ", self.suggestion_param_name)
} else {
self.suggestion_param_name.clone()
}
};
match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
for segment in path.segments {
@ -572,7 +559,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
matches!(
arg,
hir::GenericArg::Lifetime(lifetime)
if lifetime.is_anon_in_path == IsAnonInPath::Yes
if lifetime.is_syntactically_hidden()
)
}) {
self.suggestions.push((
@ -591,10 +578,10 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
if let hir::GenericArg::Lifetime(lifetime) = arg
&& lifetime.is_anonymous()
{
self.suggestions.push((
lifetime.ident.span,
make_suggestion(lifetime),
));
self.suggestions.push(
lifetime
.suggestion(&self.suggestion_param_name),
);
}
}
}
@ -602,7 +589,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
}
}
hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime)));
self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name));
}
_ => {}
}

View file

@ -117,8 +117,7 @@ fn relate_mir_and_user_args<'tcx>(
CRATE_DEF_ID,
ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
);
let instantiated_predicate =
ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
let instantiated_predicate = ocx.normalize(&cause, param_env, instantiated_predicate);
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
}

View file

@ -240,8 +240,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
continue;
}
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here.
let wc = self.where_clause_may_apply(stack, bound_trait_ref)?;
if wc.may_apply() {
candidates.vec.push(ParamCandidate(bound));

View file

@ -1,3 +1,8 @@
//! Core logic responsible for determining what it means for various type system
//! primitives to be "well formed". Actually checking whether these primitives are
//! well formed is performed elsewhere (e.g. during type checking or item well formedness
//! checking).
use std::iter;
use rustc_hir as hir;
@ -15,12 +20,13 @@ use tracing::{debug, instrument, trace};
use crate::infer::InferCtxt;
use crate::traits;
/// Returns the set of obligations needed to make `arg` well-formed.
/// If `arg` contains unresolved inference variables, this may include
/// further WF obligations. However, if `arg` IS an unresolved
/// inference variable, returns `None`, because we are not able to
/// make any progress at all. This is to prevent "livelock" where we
/// say "$0 is WF if $0 is WF".
/// make any progress at all. This is to prevent cycles where we
/// say "?0 is WF if ?0 is WF".
pub fn obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -29,14 +35,14 @@ pub fn obligations<'tcx>(
arg: GenericArg<'tcx>,
span: Span,
) -> Option<PredicateObligations<'tcx>> {
// Handle the "livelock" case (see comment above) by bailing out if necessary.
// Handle the "cycle" case (see comment above) by bailing out if necessary.
let arg = match arg.unpack() {
GenericArgKind::Type(ty) => {
match ty.kind() {
ty::Infer(ty::TyVar(_)) => {
let resolved_ty = infcx.shallow_resolve(ty);
if resolved_ty == ty {
// No progress, bail out to prevent "livelock".
// No progress, bail out to prevent cycles.
return None;
} else {
resolved_ty
@ -51,7 +57,7 @@ pub fn obligations<'tcx>(
ty::ConstKind::Infer(_) => {
let resolved = infcx.shallow_resolve_const(ct);
if resolved == ct {
// No progress.
// No progress, bail out to prevent cycles.
return None;
} else {
resolved
@ -74,7 +80,7 @@ pub fn obligations<'tcx>(
recursion_depth,
item: None,
};
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
let result = wf.normalize(infcx);
@ -97,7 +103,7 @@ pub fn unnormalized_obligations<'tcx>(
// However, if `arg` IS an unresolved inference variable, returns `None`,
// because we are not able to make any progress at all. This is to prevent
// "livelock" where we say "$0 is WF if $0 is WF".
// cycles where we say "?0 is WF if ?0 is WF".
if arg.is_non_region_infer() {
return None;
}
@ -115,7 +121,7 @@ pub fn unnormalized_obligations<'tcx>(
recursion_depth: 0,
item: None,
};
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
Some(wf.out)
}
@ -140,7 +146,7 @@ pub fn trait_obligations<'tcx>(
recursion_depth: 0,
item: Some(item),
};
wf.compute_trait_pred(trait_pred, Elaborate::All);
wf.add_wf_preds_for_trait_pred(trait_pred, Elaborate::All);
debug!(obligations = ?wf.out);
wf.normalize(infcx)
}
@ -171,7 +177,7 @@ pub fn clause_obligations<'tcx>(
// It's ok to skip the binder here because wf code is prepared for it
match clause.kind().skip_binder() {
ty::ClauseKind::Trait(t) => {
wf.compute_trait_pred(t, Elaborate::None);
wf.add_wf_preds_for_trait_pred(t, Elaborate::None);
}
ty::ClauseKind::HostEffect(..) => {
// Technically the well-formedness of this predicate is implied by
@ -179,22 +185,22 @@ pub fn clause_obligations<'tcx>(
}
ty::ClauseKind::RegionOutlives(..) => {}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
wf.compute(ty.into());
wf.add_wf_preds_for_generic_arg(ty.into());
}
ty::ClauseKind::Projection(t) => {
wf.compute_alias_term(t.projection_term);
wf.compute(t.term.into_arg());
wf.add_wf_preds_for_alias_term(t.projection_term);
wf.add_wf_preds_for_generic_arg(t.term.into_arg());
}
ty::ClauseKind::ConstArgHasType(ct, ty) => {
wf.compute(ct.into());
wf.compute(ty.into());
wf.add_wf_preds_for_generic_arg(ct.into());
wf.add_wf_preds_for_generic_arg(ty.into());
}
ty::ClauseKind::WellFormed(arg) => {
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
}
ty::ClauseKind::ConstEvaluatable(ct) => {
wf.compute(ct.into());
wf.add_wf_preds_for_generic_arg(ct.into());
}
}
@ -372,14 +378,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
fn add_wf_preds_for_trait_pred(
&mut self,
trait_pred: ty::TraitPredicate<'tcx>,
elaborate: Elaborate,
) {
let tcx = self.tcx();
let trait_ref = trait_pred.trait_ref;
// Negative trait predicates don't require supertraits to hold, just
// that their args are WF.
if trait_pred.polarity == ty::PredicatePolarity::Negative {
self.compute_negative_trait_pred(trait_ref);
self.add_wf_preds_for_negative_trait_pred(trait_ref);
return;
}
@ -445,15 +455,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// Compute the obligations that are required for `trait_ref` to be WF,
// given that it is a *negative* trait predicate.
fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
for arg in trait_ref.args {
self.compute(arg);
self.add_wf_preds_for_generic_arg(arg);
}
}
/// Pushes the obligations required for an alias (except inherent) to be WF
/// into `self.out`.
fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
// A projection is well-formed if
//
// (a) its predicates hold (*)
@ -478,13 +488,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let obligations = self.nominal_obligations(data.def_id, data.args);
self.out.extend(obligations);
self.compute_projection_args(data.args);
self.add_wf_preds_for_projection_args(data.args);
}
/// Pushes the obligations required for an inherent alias to be WF
/// into `self.out`.
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
// An inherent projection is well-formed if
//
// (a) its predicates hold (*)
@ -511,7 +521,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
data.args.visit_with(self);
}
fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
let tcx = self.tcx();
let cause = self.cause(ObligationCauseCode::WellFormed(None));
let param_env = self.param_env;
@ -557,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
#[instrument(level = "debug", skip(self))]
fn compute(&mut self, arg: GenericArg<'tcx>) {
fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) {
arg.visit_with(self);
debug!(?self.out);
}
@ -596,7 +606,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
.collect()
}
fn from_object_ty(
fn add_wf_preds_for_dyn_ty(
&mut self,
ty: Ty<'tcx>,
data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@ -651,6 +661,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
outlives,
));
}
// We don't add any wf predicates corresponding to the trait ref's generic arguments
// which allows code like this to compile:
// ```rust
// trait Trait<T: Sized> {}
// fn foo(_: &dyn Trait<[u32]>) {}
// ```
}
}
}
@ -761,7 +778,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
self.out.extend(obligations);
}
ty::Alias(ty::Inherent, data) => {
self.compute_inherent_projection(data);
self.add_wf_preds_for_inherent_projection(data);
return; // Subtree handled by compute_inherent_projection.
}
@ -895,7 +912,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
//
// Here, we defer WF checking due to higher-ranked
// regions. This is perhaps not ideal.
self.from_object_ty(t, data, r);
self.add_wf_preds_for_dyn_ty(t, data, r);
// FIXME(#27579) RFC also considers adding trait
// obligations that don't refer to Self and
@ -917,11 +934,11 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// 1. Check if they have been resolved, and if so proceed with
// THAT type.
// 2. If not, we've at least simplified things (e.g., we went
// from `Vec<$0>: WF` to `$0: WF`), so we can
// from `Vec?0>: WF` to `?0: WF`), so we can
// register a pending obligation and keep
// moving. (Goal is that an "inductive hypothesis"
// is satisfied to ensure termination.)
// See also the comment on `fn obligations`, describing "livelock"
// See also the comment on `fn obligations`, describing cycle
// prevention, which happens before this can be reached.
ty::Infer(_) => {
let cause = self.cause(ObligationCauseCode::WellFormed(None));

View file

@ -347,7 +347,8 @@ fn adjust_for_rust_scalar<'tcx>(
None
};
if let Some(kind) = kind {
attrs.pointee_align = Some(pointee.align);
attrs.pointee_align =
Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment()));
// `Box` are not necessarily dereferenceable for the entire duration of the function as
// they can be deallocated at any time. Same for non-frozen shared references (see

View file

@ -139,7 +139,7 @@ pub struct Iter<'a, T: 'a> {
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Iter").field(&self.iter.clone()).finish()
f.debug_tuple("Iter").field(&self.iter).finish()
}
}

View file

@ -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};

View file

@ -549,8 +549,6 @@ impl<T: Copy> Cell<T> {
/// # Examples
///
/// ```
/// #![feature(cell_update)]
///
/// use std::cell::Cell;
///
/// let c = Cell::new(5);
@ -558,7 +556,7 @@ impl<T: Copy> Cell<T> {
/// assert_eq!(c.get(), 6);
/// ```
#[inline]
#[unstable(feature = "cell_update", issue = "50186")]
#[stable(feature = "cell_update", since = "CURRENT_RUSTC_VERSION")]
pub fn update(&self, f: impl FnOnce(T) -> T) {
let old = self.get();
self.set(f(old));

View file

@ -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),

View file

@ -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`
///

View file

@ -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;
@ -804,7 +810,7 @@ impl f128 {
}
}
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// This returns NaN when *either* argument is NaN or if a combination of
/// +inf and -inf is provided as arguments.
@ -821,6 +827,7 @@ impl f128 {
/// # }
/// ```
#[inline]
#[doc(alias = "average")]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn midpoint(self, other: f128) -> f128 {
@ -903,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) }
@ -950,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.
@ -1373,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)
}
@ -1383,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)
}
@ -1393,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)
}
@ -1403,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)
}
@ -1413,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)
}
}

View file

@ -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;
@ -792,7 +798,7 @@ impl f16 {
}
}
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// This returns NaN when *either* argument is NaN or if a combination of
/// +inf and -inf is provided as arguments.
@ -808,6 +814,7 @@ impl f16 {
/// # }
/// ```
#[inline]
#[doc(alias = "average")]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn midpoint(self, other: f16) -> f16 {
@ -891,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) }
@ -937,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.
@ -1349,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)
}
@ -1359,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)
}
@ -1369,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)
}
@ -1379,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)
}
@ -1389,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)
}
}

View file

@ -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`.
@ -986,7 +991,7 @@ impl f32 {
}
}
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// This returns NaN when *either* argument is NaN or if a combination of
/// +inf and -inf is provided as arguments.
@ -998,6 +1003,7 @@ impl f32 {
/// assert_eq!((-5.5f32).midpoint(8.0), 1.25);
/// ```
#[inline]
#[doc(alias = "average")]
#[stable(feature = "num_midpoint", since = "1.85.0")]
#[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
pub const fn midpoint(self, other: f32) -> f32 {
@ -1096,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) }
@ -1141,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.
@ -1515,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)
}
@ -1525,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)
}
@ -1535,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)
}
@ -1545,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)
}
@ -1555,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)
}
}

View file

@ -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]
@ -1004,7 +1009,7 @@ impl f64 {
}
}
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// This returns NaN when *either* argument is NaN or if a combination of
/// +inf and -inf is provided as arguments.
@ -1016,6 +1021,7 @@ impl f64 {
/// assert_eq!((-5.5f64).midpoint(8.0), 1.25);
/// ```
#[inline]
#[doc(alias = "average")]
#[stable(feature = "num_midpoint", since = "1.85.0")]
#[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
pub const fn midpoint(self, other: f64) -> f64 {
@ -1094,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.
@ -1140,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.
@ -1514,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)
}
@ -1524,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)
}
@ -1534,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)
}
@ -1544,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)
}
@ -1554,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)
}
}

View file

@ -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

View file

@ -130,7 +130,7 @@ depending on the target pointer size.
macro_rules! midpoint_impl {
($SelfT:ty, unsigned) => {
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
/// sufficiently-large unsigned integral type. This implies that the result is
@ -146,6 +146,8 @@ macro_rules! midpoint_impl {
#[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[doc(alias = "average_floor")]
#[doc(alias = "average")]
#[inline]
pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
// Use the well known branchless algorithm from Hacker's Delight to compute
@ -154,7 +156,7 @@ macro_rules! midpoint_impl {
}
};
($SelfT:ty, signed) => {
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
/// sufficiently-large signed integral type. This implies that the result is
@ -173,6 +175,9 @@ macro_rules! midpoint_impl {
#[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[doc(alias = "average_floor")]
#[doc(alias = "average_ceil")]
#[doc(alias = "average")]
#[inline]
pub const fn midpoint(self, rhs: Self) -> Self {
// Use the well known branchless algorithm from Hacker's Delight to compute
@ -184,7 +189,7 @@ macro_rules! midpoint_impl {
}
};
($SelfT:ty, $WideT:ty, unsigned) => {
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
/// sufficiently-large unsigned integral type. This implies that the result is
@ -200,13 +205,15 @@ macro_rules! midpoint_impl {
#[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[doc(alias = "average_floor")]
#[doc(alias = "average")]
#[inline]
pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
((self as $WideT + rhs as $WideT) / 2) as $SelfT
}
};
($SelfT:ty, $WideT:ty, signed) => {
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
/// sufficiently-large signed integral type. This implies that the result is
@ -225,6 +232,9 @@ macro_rules! midpoint_impl {
#[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[doc(alias = "average_floor")]
#[doc(alias = "average_ceil")]
#[doc(alias = "average")]
#[inline]
pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
((self as $WideT + rhs as $WideT) / 2) as $SelfT

View file

@ -1589,7 +1589,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
super::int_log10::$Int(self.get())
}
/// Calculates the middle point of `self` and `rhs`.
/// Calculates the midpoint (average) between `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
/// sufficiently-large signed integral type. This implies that the result is
@ -1615,6 +1615,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
#[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[doc(alias = "average_floor")]
#[doc(alias = "average")]
#[inline]
pub const fn midpoint(self, rhs: Self) -> Self {
// SAFETY: The only way to get `0` with midpoint is to have two opposite or

View file

@ -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

View file

@ -12,7 +12,6 @@
#![feature(async_iterator)]
#![feature(bigint_helper_methods)]
#![feature(bstr)]
#![feature(cell_update)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(const_eval_select)]

View file

@ -973,6 +973,9 @@ where
/// Returns an array of length `N` with the results of each query. For soundness, at most one
/// mutable reference will be returned to any value. `None` will be used if the key is missing.
///
/// This method performs a check to ensure there are no duplicate keys, which currently has a time-complexity of O(n^2),
/// so be careful when passing many keys.
///
/// # Panics
///
/// Panics if any keys are overlapping.

View file

@ -1100,3 +1100,39 @@ pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io:
pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
sys::fs::chroot(dir.as_ref())
}
/// Create a FIFO special file at the specified path with the specified mode.
///
/// # Examples
///
/// ```no_run
/// # #![feature(unix_mkfifo)]
/// # #[cfg(not(unix))]
/// # fn main() {}
/// # #[cfg(unix)]
/// # fn main() -> std::io::Result<()> {
/// # use std::{
/// # os::unix::fs::{mkfifo, PermissionsExt},
/// # fs::{File, Permissions, remove_file},
/// # io::{Write, Read},
/// # };
/// # let _ = remove_file("/tmp/fifo");
/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?;
///
/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?;
/// let mut rx = File::open("/tmp/fifo")?;
///
/// wx.write_all(b"hello, world!")?;
/// drop(wx);
///
/// let mut s = String::new();
/// rx.read_to_string(&mut s)?;
///
/// assert_eq!(s, "hello, world!");
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "unix_mkfifo", issue = "139324")]
pub fn mkfifo<P: AsRef<Path>>(path: P, permissions: Permissions) -> io::Result<()> {
sys::fs::mkfifo(path.as_ref(), permissions.mode())
}

View file

@ -55,3 +55,23 @@ fn write_vectored_at() {
let content = fs::read(&filename).unwrap();
assert_eq!(&content, expected);
}
#[test]
fn test_mkfifo() {
let tmp_dir = crate::test_helpers::tmpdir();
let fifo = tmp_dir.path().join("fifo");
mkfifo(&fifo, Permissions::from_mode(0o774)).unwrap();
let mut wx = fs::File::options().read(true).write(true).open(&fifo).unwrap();
let mut rx = fs::File::open(fifo).unwrap();
wx.write_all(b"hello, world!").unwrap();
drop(wx);
let mut s = String::new();
rx.read_to_string(&mut s).unwrap();
assert_eq!(s, "hello, world!");
}

View file

@ -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 {

View file

@ -9,7 +9,7 @@ cfg_if::cfg_if! {
if #[cfg(target_family = "unix")] {
mod unix;
use unix as imp;
pub use unix::{chown, fchown, lchown};
pub use unix::{chown, fchown, lchown, mkfifo};
#[cfg(not(target_os = "fuchsia"))]
pub use unix::chroot;
pub(crate) use unix::debug_assert_fd_is_open;

View file

@ -2137,6 +2137,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks"))
}
pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> {
run_path_with_cstr(path, &|path| {
cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ())
})
}
pub use remove_dir_impl::remove_dir_all;
// Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri

View file

@ -1,9 +0,0 @@
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";
}

@ -1 +1 @@
Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1
Subproject commit 1245618ccf5b2df7ab1ebb0279b9f3f726670161

View file

@ -683,7 +683,7 @@ impl Step for Editor {
match EditorKind::prompt_user() {
Ok(editor_kind) => {
if let Some(editor_kind) = editor_kind {
while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {}
while !t!(create_editor_settings_maybe(config, &editor_kind)) {}
} else {
println!("Ok, skipping editor setup!");
}
@ -695,7 +695,7 @@ impl Step for Editor {
/// Create the recommended editor LSP config file for rustc development, or just print it
/// If this method should be re-called, it returns `false`.
fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result<bool> {
fn create_editor_settings_maybe(config: &Config, editor: &EditorKind) -> io::Result<bool> {
let hashes = editor.hashes();
let (current_hash, historical_hashes) = hashes.split_last().unwrap();
let settings_path = editor.settings_path(config);
@ -752,7 +752,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
// exists but user modified, back it up
Some(false) => {
// exists and is not current version or outdated, so back it up
let backup = settings_path.clone().with_extension(editor.backup_extension());
let backup = settings_path.with_extension(editor.backup_extension());
eprintln!(
"WARNING: copying `{}` to `{}`",
settings_path.file_name().unwrap().to_str().unwrap(),

View file

@ -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)

View file

@ -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();

View file

@ -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,
}

View file

@ -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,
}

View file

@ -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,
}

View file

@ -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(),

View file

@ -6,25 +6,37 @@
ui/codegen/assembly test suites. It provides `core` stubs for tests that need to
build for cross-compiled targets but do not need/want to run.
A test can use [`minicore`] by specifying the `//@ add-core-stubs` directive.
Then, mark the test with `#![feature(no_core)]` + `#![no_std]` + `#![no_core]`.
Due to Edition 2015 extern prelude rules, you will probably need to declare
`minicore` as an extern crate.
Due to the `no_std` + `no_core` nature of these tests, `//@ add-core-stubs`
implies and requires that the test will be built with `-C panic=abort`.
Unwinding panics are not supported.
If you find a `core` item to be missing from the [`minicore`] stub, consider
adding it to the test auxiliary if it's likely to be used or is already needed
by more than one test.
<div class="warning">
Please note that [`minicore`] is only intended for `core` items, and explicitly
**not** `std` or `alloc` items because `core` items are applicable to a wider
range of tests.
</div>
A test can use [`minicore`] by specifying the `//@ add-core-stubs` directive.
Then, mark the test with `#![feature(no_core)]` + `#![no_std]` + `#![no_core]`.
Due to Edition 2015 extern prelude rules, you will probably need to declare
`minicore` as an extern crate.
## Implied compiler flags
Due to the `no_std` + `no_core` nature of these tests, `//@ add-core-stubs`
implies and requires that the test will be built with `-C panic=abort`.
**Unwinding panics are not supported.**
Tests will also be built with `-C force-unwind-tables=yes` to preserve CFI
directives in assembly tests.
TL;DR: `//@ add-core-stubs` implies two compiler flags:
1. `-C panic=abort`
2. `-C force-unwind-tables=yes`
## Adding more `core` stubs
If you find a `core` item to be missing from the [`minicore`] stub, consider
adding it to the test auxiliary if it's likely to be used or is already needed
by more than one test.
## Example codegen test that uses `minicore`
```rust,no_run

View file

@ -34,7 +34,7 @@ target | notes
-------|-------
[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
[`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
[`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
@ -43,6 +43,8 @@ target | notes
[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue].
[^win32-msvc-alignment]: Due to non-standard behavior of MSVC, native C code on this target can cause types with an alignment of more than 4 bytes to be incorrectly aligned to only 4 bytes (this affects, e.g., `u64` and `i64`). Rust applies some mitigations to reduce the impact of this issue, but this can still cause unsoundness due to unsafe code that (correctly) assumes that references are always properly aligned. See [issue #112480](https://github.com/rust-lang/rust/issues/112480).
[77071]: https://github.com/rust-lang/rust/issues/77071
[x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567
@ -95,7 +97,7 @@ target | notes
[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5)
[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17)
@ -169,7 +171,7 @@ target | std | notes
[`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
[`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI]
`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI]
[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat)
[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) [^win32-msvc-alignment]
[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI)
[`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
@ -317,9 +319,9 @@ target | std | host | notes
[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI]
[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI]
`i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI]
[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI]
[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
[`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
[`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI]
[`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony
[`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux

View file

@ -20,8 +20,9 @@ The `target_os` of the target is `cygwin`, and it is `unix`.
## Building the target
For cross-compilation you want LLVM with [llvm/llvm-project#121439 (merged)](https://github.com/llvm/llvm-project/pull/121439) applied to fix the LLVM codegen on importing external global variables from DLLs.
No native builds on Cygwin now. It should be possible theoretically though, but might need a lot of patches.
For cross-compilation you want LLVM at least 20.1.0-rc1.
No native builds on Cygwin now.
The tracking issue for host tools on Cygwin is [#137819](https://github.com/rust-lang/rust/issues/137819).
## Building Rust programs

View file

@ -54,4 +54,25 @@ if let [b] = &mut *v {
assert_eq!(v, [Box::new(Some(2))]);
```
Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str`
is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is
expected. This lets them be used in `deref!(_)` patterns:
```rust
# #![feature(deref_patterns)]
# #![allow(incomplete_features)]
match ("test".to_string(), b"test".to_vec()) {
(deref!("test"), deref!(b"test")) => {}
_ => panic!(),
}
// Matching on slices and arrays using literals is possible elsewhere as well:
match *"test" {
"test" => {}
_ => panic!(),
}
```
Implicit deref pattern syntax is not yet supported for string or byte string literals.
[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors

View file

@ -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

View file

@ -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");

View file

@ -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 {

View file

@ -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 {

View file

@ -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`

View file

@ -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`

View file

@ -3,6 +3,7 @@
#![allow(
dead_code,
clippy::borrow_as_ptr,
unnecessary_transmutes,
clippy::needless_lifetimes,
clippy::missing_transmute_annotations
)]

View file

@ -1,5 +1,5 @@
error: transmute from a reference to a pointer
--> tests/ui/transmute.rs:32:27
--> tests/ui/transmute.rs:33:27
|
LL | let _: *const T = core::mem::transmute(t);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
@ -8,61 +8,61 @@ LL | let _: *const T = core::mem::transmute(t);
= help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
error: transmute from a reference to a pointer
--> tests/ui/transmute.rs:35:25
--> tests/ui/transmute.rs:36:25
|
LL | let _: *mut T = core::mem::transmute(t);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
error: transmute from a reference to a pointer
--> tests/ui/transmute.rs:38:27
--> tests/ui/transmute.rs:39:27
|
LL | let _: *const U = core::mem::transmute(t);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
error: transmute from a type (`std::vec::Vec<i32>`) to itself
--> tests/ui/transmute.rs:46:27
--> tests/ui/transmute.rs:47:27
|
LL | let _: Vec<i32> = core::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
--> tests/ui/transmute.rs:49:27
--> tests/ui/transmute.rs:50:27
|
LL | let _: Vec<i32> = core::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
--> tests/ui/transmute.rs:52:27
--> tests/ui/transmute.rs:53:27
|
LL | let _: Vec<i32> = std::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
--> tests/ui/transmute.rs:55:27
--> tests/ui/transmute.rs:56:27
|
LL | let _: Vec<i32> = std::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
--> tests/ui/transmute.rs:58:27
--> tests/ui/transmute.rs:59:27
|
LL | let _: Vec<i32> = my_transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^
error: transmute from an integer to a pointer
--> tests/ui/transmute.rs:61:31
--> tests/ui/transmute.rs:62:31
|
LL | let _: *const usize = std::mem::transmute(5_isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
error: transmute from an integer to a pointer
--> tests/ui/transmute.rs:66:31
--> tests/ui/transmute.rs:67:31
|
LL | let _: *const usize = std::mem::transmute(1 + 1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
--> tests/ui/transmute.rs:98:24
--> tests/ui/transmute.rs:99:24
|
LL | let _: Usize = core::mem::transmute(int_const_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -71,25 +71,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr);
= help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
--> tests/ui/transmute.rs:101:24
--> tests/ui/transmute.rs:102:24
|
LL | let _: Usize = core::mem::transmute(int_mut_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
--> tests/ui/transmute.rs:104:31
--> tests/ui/transmute.rs:105:31
|
LL | let _: *const Usize = core::mem::transmute(my_int());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
--> tests/ui/transmute.rs:107:29
--> tests/ui/transmute.rs:108:29
|
LL | let _: *mut Usize = core::mem::transmute(my_int());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a `u8` to a `bool`
--> tests/ui/transmute.rs:114:28
--> tests/ui/transmute.rs:115:28
|
LL | let _: bool = unsafe { std::mem::transmute(0_u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@ -98,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) };
= help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
error: transmute from a `u16` to a `f16`
--> tests/ui/transmute.rs:121:31
--> tests/ui/transmute.rs:122:31
|
LL | let _: f16 = unsafe { std::mem::transmute(0_u16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
@ -107,97 +107,97 @@ LL | let _: f16 = unsafe { std::mem::transmute(0_u16) };
= help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
error: transmute from a `i16` to a `f16`
--> tests/ui/transmute.rs:124:31
--> tests/ui/transmute.rs:125:31
|
LL | let _: f16 = unsafe { std::mem::transmute(0_i16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)`
error: transmute from a `u32` to a `f32`
--> tests/ui/transmute.rs:127:31
--> tests/ui/transmute.rs:128:31
|
LL | let _: f32 = unsafe { std::mem::transmute(0_u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
error: transmute from a `i32` to a `f32`
--> tests/ui/transmute.rs:130:31
--> tests/ui/transmute.rs:131:31
|
LL | let _: f32 = unsafe { std::mem::transmute(0_i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
error: transmute from a `u64` to a `f64`
--> tests/ui/transmute.rs:133:31
--> tests/ui/transmute.rs:134:31
|
LL | let _: f64 = unsafe { std::mem::transmute(0_u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
error: transmute from a `i64` to a `f64`
--> tests/ui/transmute.rs:136:31
--> tests/ui/transmute.rs:137:31
|
LL | let _: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
error: transmute from a `u128` to a `f128`
--> tests/ui/transmute.rs:139:32
--> tests/ui/transmute.rs:140:32
|
LL | let _: f128 = unsafe { std::mem::transmute(0_u128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)`
error: transmute from a `i128` to a `f128`
--> tests/ui/transmute.rs:142:32
--> tests/ui/transmute.rs:143:32
|
LL | let _: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `u16` to a `f16`
--> tests/ui/transmute.rs:147:39
--> tests/ui/transmute.rs:148:39
|
LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
error: transmute from a `u32` to a `f32`
--> tests/ui/transmute.rs:150:39
--> tests/ui/transmute.rs:151:39
|
LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
error: transmute from a `i64` to a `f64`
--> tests/ui/transmute.rs:153:39
--> tests/ui/transmute.rs:154:39
|
LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
error: transmute from a `i128` to a `f128`
--> tests/ui/transmute.rs:156:41
--> tests/ui/transmute.rs:157:41
|
LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `i16` to a `f16`
--> tests/ui/transmute.rs:160:22
--> tests/ui/transmute.rs:161:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
error: transmute from a `i32` to a `f32`
--> tests/ui/transmute.rs:165:22
--> tests/ui/transmute.rs:166:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
error: transmute from a `u64` to a `f64`
--> tests/ui/transmute.rs:170:22
--> tests/ui/transmute.rs:171:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
error: transmute from a `u128` to a `f128`
--> tests/ui/transmute.rs:175:22
--> tests/ui/transmute.rs:176:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
error: transmute from a `u8` to a `[u8; 1]`
--> tests/ui/transmute.rs:184:30
--> tests/ui/transmute.rs:185:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@ -206,121 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8);
= help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
error: transmute from a `u32` to a `[u8; 4]`
--> tests/ui/transmute.rs:187:30
--> tests/ui/transmute.rs:188:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
--> tests/ui/transmute.rs:190:31
--> tests/ui/transmute.rs:191:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
--> tests/ui/transmute.rs:193:30
--> tests/ui/transmute.rs:194:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
--> tests/ui/transmute.rs:196:30
--> tests/ui/transmute.rs:197:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
--> tests/ui/transmute.rs:199:31
--> tests/ui/transmute.rs:200:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
--> tests/ui/transmute.rs:202:30
--> tests/ui/transmute.rs:203:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
--> tests/ui/transmute.rs:205:30
--> tests/ui/transmute.rs:206:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
--> tests/ui/transmute.rs:208:30
--> tests/ui/transmute.rs:209:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
--> tests/ui/transmute.rs:211:31
--> tests/ui/transmute.rs:212:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `u8` to a `[u8; 1]`
--> tests/ui/transmute.rs:217:30
--> tests/ui/transmute.rs:218:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
error: transmute from a `u32` to a `[u8; 4]`
--> tests/ui/transmute.rs:220:30
--> tests/ui/transmute.rs:221:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
--> tests/ui/transmute.rs:223:31
--> tests/ui/transmute.rs:224:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
--> tests/ui/transmute.rs:226:30
--> tests/ui/transmute.rs:227:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
--> tests/ui/transmute.rs:229:30
--> tests/ui/transmute.rs:230:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
--> tests/ui/transmute.rs:232:31
--> tests/ui/transmute.rs:233:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
--> tests/ui/transmute.rs:235:30
--> tests/ui/transmute.rs:236:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
--> tests/ui/transmute.rs:238:30
--> tests/ui/transmute.rs:239:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
--> tests/ui/transmute.rs:241:30
--> tests/ui/transmute.rs:242:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
--> tests/ui/transmute.rs:244:31
--> tests/ui/transmute.rs:245:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `&[u8]` to a `&str`
--> tests/ui/transmute.rs:253:28
--> tests/ui/transmute.rs:254:28
|
LL | let _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@ -329,13 +329,13 @@ LL | let _: &str = unsafe { std::mem::transmute(B) };
= help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
error: transmute from a `&mut [u8]` to a `&mut str`
--> tests/ui/transmute.rs:256:32
--> tests/ui/transmute.rs:257:32
|
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
error: transmute from a `&[u8]` to a `&str`
--> tests/ui/transmute.rs:259:30
--> tests/ui/transmute.rs:260:30
|
LL | const _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`

View file

@ -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)]

View file

@ -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)]

Some files were not shown because too many files have changed in this diff Show more