Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-07-01 05:05:50 +00:00
commit e6371c9379
344 changed files with 4270 additions and 2479 deletions

View file

@ -690,6 +690,7 @@ Xinye Tao <xy.tao@outlook.com>
Xuefeng Wu <benewu@gmail.com> Xuefeng Wu <xfwu@thoughtworks.com>
Xuefeng Wu <benewu@gmail.com> XuefengWu <benewu@gmail.com>
York Xiang <bombless@126.com>
Yotam Ofek <yotam.ofek@gmail.com> <yotamofek@microsoft.com>
Youngsoo Son <ysson83@gmail.com> <ysoo.son@samsung.com>
Youngsuk Kim <joseph942010@gmail.com>
Yuki Okushi <jtitor@2k36.org>

View file

@ -256,6 +256,9 @@ pub enum AttributeKind {
/// Represents `#[link_name]`.
LinkName { name: Symbol, span: Span },
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
LinkSection { name: Symbol, span: Span },
/// Represents `#[loop_match]`.
LoopMatch(Span),

View file

@ -24,6 +24,7 @@ impl AttributeKind {
DocComment { .. } => Yes,
ExportName { .. } => Yes,
Inline(..) => No,
LinkSection { .. } => No,
MacroTransparency(..) => Yes,
Repr(..) => No,
Stability { .. } => Yes,

View file

@ -99,6 +99,8 @@ attr_parsing_non_ident_feature =
attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_null_on_link_section = `link_section` may not contain null characters
attr_parsing_repr_ident =
meta item in `repr` must be an identifier

View file

@ -1,11 +1,12 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_attr_data_structures::AttributeKind::LinkName;
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::{Symbol, sym};
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics::NullOnLinkSection;
pub(crate) struct LinkNameParser;
@ -28,3 +29,31 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
Some(LinkName { name, span: cx.attr_span })
}
}
pub(crate) struct LinkSectionParser;
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(name) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
if name.as_str().contains('\0') {
// `#[link_section = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnLinkSection { span: cx.attr_span });
return None;
}
Some(LinkSection { name, span: cx.attr_span })
}
}

View file

@ -22,7 +22,7 @@ use crate::attributes::codegen_attrs::{
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::link_attrs::LinkNameParser;
use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser;
@ -123,6 +123,7 @@ attribute_parsers!(
Single<ExportNameParser>,
Single<InlineParser>,
Single<LinkNameParser>,
Single<LinkSectionParser>,
Single<LoopMatchParser>,
Single<MayDangleParser>,
Single<MustUseParser>,

View file

@ -452,6 +452,13 @@ pub(crate) struct NullOnExport {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_link_section, code = E0648)]
pub(crate) struct NullOnLinkSection {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {

View file

@ -660,7 +660,7 @@ pub mod intrinsics {
#[rustc_intrinsic]
pub unsafe fn ctlz_nonzero<T>(x: T) -> u32;
#[rustc_intrinsic]
pub fn needs_drop<T: ?::Sized>() -> bool;
pub const fn needs_drop<T: ?::Sized>() -> bool;
#[rustc_intrinsic]
pub fn bitreverse<T>(x: T) -> T;
#[rustc_intrinsic]

View file

@ -1,4 +1,13 @@
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
#![feature(
no_core,
lang_items,
never_type,
linkage,
extern_types,
thread_local,
repr_simd,
rustc_private
)]
#![no_core]
#![allow(dead_code, non_camel_case_types, internal_features)]
@ -207,10 +216,14 @@ fn main() {
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());
assert!(intrinsics::needs_drop::<NoisyDrop>());
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
assert!(!u8_needs_drop);
let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() };
assert!(!slice_needs_drop);
let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() };
assert!(noisy_drop);
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
assert!(noisy_unsized_drop);
Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;

View file

@ -133,7 +133,7 @@ pub(crate) fn codegen_const_value<'tcx>(
}
}
Scalar::Ptr(ptr, _size) => {
let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
let (prov, offset) = ptr.prov_and_relative_offset();
let alloc_id = prov.alloc_id();
let base_addr = match fx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {

View file

@ -812,21 +812,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
dest.write_cvalue(fx, val);
}
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
intrinsic_args!(fx, args => (); intrinsic);
let const_val = fx
.tcx
.const_eval_instance(
ty::TypingEnv::fully_monomorphized(),
instance,
source_info.span,
)
.unwrap();
let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
ret.write_cvalue(fx, val);
}
sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
intrinsic_args!(fx, args => (ptr, base); intrinsic);
let ptr = ptr.load_scalar(fx);

View file

@ -6,6 +6,7 @@ resolver = "2"
[dependencies]
core = { path = "./sysroot_src/library/core" }
compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" }
alloc = { path = "./sysroot_src/library/alloc" }
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
test = { path = "./sysroot_src/library/test" }

View file

@ -9,8 +9,8 @@ use crate::build;
use crate::config::{Channel, ConfigInfo};
use crate::utils::{
create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file,
run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env,
rustc_version_info, split_args, walk_dir,
run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info,
split_args, walk_dir,
};
type Env = HashMap<String, String>;
@ -485,30 +485,6 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?;
}
let mut patches = Vec::new();
walk_dir(
"patches/tests",
&mut |_| Ok(()),
&mut |file_path: &Path| {
patches.push(file_path.to_path_buf());
Ok(())
},
false,
)?;
patches.sort();
// TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils
// module.
for file_path in patches {
println!("[GIT] apply `{}`", file_path.display());
let path = Path::new("../..").join(file_path);
run_command_with_output(&[&"git", &"apply", &path], rust_dir)?;
run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?;
run_command_with_output(
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
rust_dir,
)?;
}
let cargo = String::from_utf8(
run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout,
)

View file

@ -6,6 +6,7 @@
)]
#![no_core]
#![allow(dead_code, internal_features, non_camel_case_types)]
#![rustfmt::skip]
extern crate mini_core;
@ -197,10 +198,10 @@ fn main() {
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());
assert!(intrinsics::needs_drop::<NoisyDrop>());
assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
assert!(!const { intrinsics::needs_drop::<u8>() });
assert!(!const { intrinsics::needs_drop::<[u8]>() });
assert!(const { intrinsics::needs_drop::<NoisyDrop>() });
assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() });
Unique {
pointer: 0 as *const &str,

View file

@ -1,25 +0,0 @@
From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Fri, 13 Jun 2025 20:25:33 -0400
Subject: [PATCH] Workaround to make a run-make test pass
---
tests/run-make/linker-warning/rmake.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
index bc21739fefc..0946a7e2a48 100644
--- a/tests/run-make/linker-warning/rmake.rs
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -55,7 +55,7 @@ fn main() {
diff()
.expected_file("short-error.txt")
.actual_text("(linker error)", out.stderr())
- .normalize(r#"/rustc[^/]*/"#, "/rustc/")
+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/")
.normalize(
regex::escape(run_make_support::build_root().to_str().unwrap()),
"/build-root",
--
2.49.0

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2025-06-02"
channel = "nightly-2025-06-28"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -1,7 +1,9 @@
#[cfg(feature = "master")]
use gccjit::FnAttribute;
use gccjit::{ToLValue, ToRValue, Type};
use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call};
#[cfg(feature = "master")]
use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
use rustc_abi::{Reg, RegKind};
use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;

View file

@ -538,11 +538,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
}
fn ret(&mut self, mut value: RValue<'gcc>) {
if self.structs_as_pointer.borrow().contains(&value) {
// NOTE: hack to workaround a limitation of the rustc API: see comment on
// CodegenCx.structs_as_pointer
value = value.dereference(self.location).to_rvalue();
}
let expected_return_type = self.current_func().get_return_type();
if !expected_return_type.is_compatible_with(value.get_type()) {
// NOTE: due to opaque pointers now being used, we need to cast here.
@ -700,7 +695,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let a = self.gcc_int_cast(a, a_type);
let b_type = b.get_type().to_unsigned(self);
let b = self.gcc_int_cast(b, b_type);
a / b
self.gcc_udiv(a, b)
}
fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@ -712,8 +707,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
// should be the same.
let typ = a.get_type().to_signed(self);
let b = self.context.new_cast(self.location, b, typ);
a / b
let b = self.gcc_int_cast(b, typ);
self.gcc_sdiv(a, b)
}
fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
@ -1119,13 +1114,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}
fn store(&mut self, mut val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
if self.structs_as_pointer.borrow().contains(&val) {
// NOTE: hack to workaround a limitation of the rustc API: see comment on
// CodegenCx.structs_as_pointer
val = val.dereference(self.location).to_rvalue();
}
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
@ -1508,16 +1497,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
element.get_address(self.location)
} else if value_type.dyncast_vector().is_some() {
panic!();
} else if let Some(pointer_type) = value_type.get_pointee() {
if let Some(struct_type) = pointer_type.is_struct() {
// NOTE: hack to workaround a limitation of the rustc API: see comment on
// CodegenCx.structs_as_pointer
aggregate_value
.dereference_field(self.location, struct_type.get_field(idx as i32))
.to_rvalue()
} else {
panic!("Unexpected type {:?}", value_type);
}
} else if let Some(struct_type) = value_type.is_struct() {
aggregate_value
.access_field(self.location, struct_type.get_field(idx as i32))
@ -1537,21 +1516,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
assert_eq!(idx as usize as u64, idx);
let value_type = aggregate_value.get_type();
let new_val = self.current_func().new_local(None, value_type, "aggregate_value");
self.block.add_assignment(None, new_val, aggregate_value);
let lvalue = if value_type.dyncast_array().is_some() {
let index = self
.context
.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
self.context.new_array_access(self.location, aggregate_value, index)
self.context.new_array_access(self.location, new_val, index)
} else if value_type.dyncast_vector().is_some() {
panic!();
} else if let Some(pointer_type) = value_type.get_pointee() {
if let Some(struct_type) = pointer_type.is_struct() {
// NOTE: hack to workaround a limitation of the rustc API: see comment on
// CodegenCx.structs_as_pointer
aggregate_value.dereference_field(self.location, struct_type.get_field(idx as i32))
} else {
panic!("Unexpected type {:?}", value_type);
}
} else if let Some(struct_type) = value_type.is_struct() {
new_val.access_field(None, struct_type.get_field(idx as i32))
} else {
panic!("Unexpected type {:?}", value_type);
};
@ -1568,7 +1544,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.llbb().add_assignment(self.location, lvalue, value);
aggregate_value
new_val.to_rvalue()
}
fn set_personality_fn(&mut self, _personality: Function<'gcc>) {

View file

@ -117,15 +117,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
if typ.is_struct().is_some() {
// NOTE: hack to workaround a limitation of the rustc API: see comment on
// CodegenCx.structs_as_pointer
let pointer = local.get_address(None);
self.structs_as_pointer.borrow_mut().insert(pointer);
pointer
} else {
local.to_rvalue()
}
local.to_rvalue()
}
fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> {
@ -248,7 +240,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
}
}
Scalar::Ptr(ptr, _size) => {
let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
let (prov, offset) = ptr.prov_and_relative_offset();
let alloc_id = prov.alloc_id();
let base_addr = match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {

View file

@ -124,14 +124,6 @@ pub struct CodegenCx<'gcc, 'tcx> {
pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
/// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
/// `const_undef()` returns struct as pointer so that they can later be assigned a value (in
/// e.g. Builder::insert_value).
/// As such, this set remembers which of these pointers were returned by this function so that
/// they can be dereferenced later.
/// FIXME(antoyo): fix the rustc API to avoid having this hack.
pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
#[cfg(feature = "master")]
pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>,
/// The alignment of a u128/i128 type.
@ -304,7 +296,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
#[cfg(feature = "master")]
rust_try_fn: Cell::new(None),
pointee_infos: Default::default(),
structs_as_pointer: Default::default(),
#[cfg(feature = "master")]
cleanup_blocks: Default::default(),
};

View file

@ -1,9 +1,9 @@
// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`
// DO NOT EDIT IT!
/// Translate a given LLVM intrinsic name to an equivalent GCC one.
fn map_arch_intrinsic(name: &str) -> &str {
let Some(name) = name.strip_prefix("llvm.") else {
unimplemented!("***** unsupported LLVM intrinsic {}", name)
fn map_arch_intrinsic(full_name: &str) -> &'static str {
let Some(name) = full_name.strip_prefix("llvm.") else {
unimplemented!("***** unsupported LLVM intrinsic {}", full_name)
};
let Some((arch, name)) = name.split_once('.') else {
unimplemented!("***** unsupported LLVM intrinsic {}", name)
@ -11,7 +11,7 @@ fn map_arch_intrinsic(name: &str) -> &str {
match arch {
"AMDGPU" => {
#[allow(non_snake_case)]
fn AMDGPU(name: &str) -> &str {
fn AMDGPU(name: &str, full_name: &str) -> &'static str {
match name {
// AMDGPU
"div.fixup.f32" => "__builtin_amdgpu_div_fixup",
@ -42,14 +42,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"trig.preop.f64" => "__builtin_amdgpu_trig_preop",
"trig.preop.v2f64" => "__builtin_amdgpu_trig_preop",
"trig.preop.v4f32" => "__builtin_amdgpu_trig_preop",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
AMDGPU(name)
AMDGPU(name, full_name)
}
"aarch64" => {
#[allow(non_snake_case)]
fn aarch64(name: &str) -> &str {
fn aarch64(name: &str, full_name: &str) -> &'static str {
match name {
// aarch64
"chkfeat" => "__builtin_arm_chkfeat",
@ -75,14 +75,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"tcommit" => "__builtin_arm_tcommit",
"tstart" => "__builtin_arm_tstart",
"ttest" => "__builtin_arm_ttest",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
aarch64(name)
aarch64(name, full_name)
}
"amdgcn" => {
#[allow(non_snake_case)]
fn amdgcn(name: &str) -> &str {
fn amdgcn(name: &str, full_name: &str) -> &'static str {
match name {
// amdgcn
"alignbyte" => "__builtin_amdgcn_alignbyte",
@ -99,6 +99,8 @@ fn map_arch_intrinsic(name: &str) -> &str {
"cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8",
"cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4",
"cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32",
"cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8",
"cvt.pk.f16.fp8" => "__builtin_amdgcn_cvt_pk_f16_fp8",
"cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8",
"cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8",
"cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32",
@ -292,6 +294,7 @@ fn map_arch_intrinsic(name: &str) -> &str {
"s.sendmsg" => "__builtin_amdgcn_s_sendmsg",
"s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt",
"s.setprio" => "__builtin_amdgcn_s_setprio",
"s.setprio.inc.wg" => "__builtin_amdgcn_s_setprio_inc_wg",
"s.setreg" => "__builtin_amdgcn_s_setreg",
"s.sleep" => "__builtin_amdgcn_s_sleep",
"s.sleep.var" => "__builtin_amdgcn_s_sleep_var",
@ -356,14 +359,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"workitem.id.x" => "__builtin_amdgcn_workitem_id_x",
"workitem.id.y" => "__builtin_amdgcn_workitem_id_y",
"workitem.id.z" => "__builtin_amdgcn_workitem_id_z",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
amdgcn(name)
amdgcn(name, full_name)
}
"arm" => {
#[allow(non_snake_case)]
fn arm(name: &str) -> &str {
fn arm(name: &str, full_name: &str) -> &'static str {
match name {
// arm
"cdp" => "__builtin_arm_cdp",
@ -465,14 +468,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"usub8" => "__builtin_arm_usub8",
"uxtab16" => "__builtin_arm_uxtab16",
"uxtb16" => "__builtin_arm_uxtb16",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
arm(name)
arm(name, full_name)
}
"bpf" => {
#[allow(non_snake_case)]
fn bpf(name: &str) -> &str {
fn bpf(name: &str, full_name: &str) -> &'static str {
match name {
// bpf
"btf.type.id" => "__builtin_bpf_btf_type_id",
@ -487,25 +490,25 @@ fn map_arch_intrinsic(name: &str) -> &str {
"preserve.field.info" => "__builtin_bpf_preserve_field_info",
"preserve.type.info" => "__builtin_bpf_preserve_type_info",
"pseudo" => "__builtin_bpf_pseudo",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
bpf(name)
bpf(name, full_name)
}
"cuda" => {
#[allow(non_snake_case)]
fn cuda(name: &str) -> &str {
fn cuda(name: &str, full_name: &str) -> &'static str {
match name {
// cuda
"syncthreads" => "__syncthreads",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
cuda(name)
cuda(name, full_name)
}
"hexagon" => {
#[allow(non_snake_case)]
fn hexagon(name: &str) -> &str {
fn hexagon(name: &str, full_name: &str) -> &'static str {
match name {
// hexagon
"A2.abs" => "__builtin_HEXAGON_A2_abs",
@ -2479,14 +2482,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"prefetch" => "__builtin_HEXAGON_prefetch",
"vmemcpy" => "__builtin_hexagon_vmemcpy",
"vmemset" => "__builtin_hexagon_vmemset",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
hexagon(name)
hexagon(name, full_name)
}
"loongarch" => {
#[allow(non_snake_case)]
fn loongarch(name: &str) -> &str {
fn loongarch(name: &str, full_name: &str) -> &'static str {
match name {
// loongarch
"asrtgt.d" => "__builtin_loongarch_asrtgt_d",
@ -3988,14 +3991,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"movfcsr2gr" => "__builtin_loongarch_movfcsr2gr",
"movgr2fcsr" => "__builtin_loongarch_movgr2fcsr",
"syscall" => "__builtin_loongarch_syscall",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
loongarch(name)
loongarch(name, full_name)
}
"mips" => {
#[allow(non_snake_case)]
fn mips(name: &str) -> &str {
fn mips(name: &str, full_name: &str) -> &'static str {
match name {
// mips
"absq.s.ph" => "__builtin_mips_absq_s_ph",
@ -4669,14 +4672,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"wrdsp" => "__builtin_mips_wrdsp",
"xor.v" => "__builtin_msa_xor_v",
"xori.b" => "__builtin_msa_xori_b",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
mips(name)
mips(name, full_name)
}
"nvvm" => {
#[allow(non_snake_case)]
fn nvvm(name: &str) -> &str {
fn nvvm(name: &str, full_name: &str) -> &'static str {
match name {
// nvvm
"abs.i" => "__nvvm_abs_i",
@ -5024,6 +5027,7 @@ fn map_arch_intrinsic(name: &str) -> &str {
"nanosleep" => "__nvvm_nanosleep",
"neg.bf16" => "__nvvm_neg_bf16",
"neg.bf16x2" => "__nvvm_neg_bf16x2",
"pm.event.mask" => "__nvvm_pm_event_mask",
"popc.i" => "__nvvm_popc_i",
"popc.ll" => "__nvvm_popc_ll",
"prmt" => "__nvvm_prmt",
@ -5448,14 +5452,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"vote.ballot.sync" => "__nvvm_vote_ballot_sync",
"vote.uni" => "__nvvm_vote_uni",
"vote.uni.sync" => "__nvvm_vote_uni_sync",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
nvvm(name)
nvvm(name, full_name)
}
"ppc" => {
#[allow(non_snake_case)]
fn ppc(name: &str) -> &str {
fn ppc(name: &str, full_name: &str) -> &'static str {
match name {
// ppc
"addex" => "__builtin_ppc_addex",
@ -5842,7 +5846,10 @@ fn map_arch_intrinsic(name: &str) -> &str {
"mulhdu" => "__builtin_ppc_mulhdu",
"mulhw" => "__builtin_ppc_mulhw",
"mulhwu" => "__builtin_ppc_mulhwu",
"national2packed" => "__builtin_ppc_national2packed",
"pack.longdouble" => "__builtin_pack_longdouble",
"packed2national" => "__builtin_ppc_packed2national",
"packed2zoned" => "__builtin_ppc_packed2zoned",
"pdepd" => "__builtin_pdepd",
"pextd" => "__builtin_pextd",
"qpx.qvfabs" => "__builtin_qpx_qvfabs",
@ -6035,14 +6042,15 @@ fn map_arch_intrinsic(name: &str) -> &str {
"vsx.xxinsertw" => "__builtin_vsx_xxinsertw",
"vsx.xxleqv" => "__builtin_vsx_xxleqv",
"vsx.xxpermx" => "__builtin_vsx_xxpermx",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
"zoned2packed" => "__builtin_ppc_zoned2packed",
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
ppc(name)
ppc(name, full_name)
}
"ptx" => {
#[allow(non_snake_case)]
fn ptx(name: &str) -> &str {
fn ptx(name: &str, full_name: &str) -> &'static str {
match name {
// ptx
"bar.sync" => "__builtin_ptx_bar_sync",
@ -6063,14 +6071,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"read.pm3" => "__builtin_ptx_read_pm3",
"read.smid" => "__builtin_ptx_read_smid",
"read.warpid" => "__builtin_ptx_read_warpid",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
ptx(name)
ptx(name, full_name)
}
"r600" => {
#[allow(non_snake_case)]
fn r600(name: &str) -> &str {
fn r600(name: &str, full_name: &str) -> &'static str {
match name {
// r600
"group.barrier" => "__builtin_r600_group_barrier",
@ -6088,14 +6096,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"read.tidig.x" => "__builtin_r600_read_tidig_x",
"read.tidig.y" => "__builtin_r600_read_tidig_y",
"read.tidig.z" => "__builtin_r600_read_tidig_z",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
r600(name)
r600(name, full_name)
}
"riscv" => {
#[allow(non_snake_case)]
fn riscv(name: &str) -> &str {
fn riscv(name: &str, full_name: &str) -> &'static str {
match name {
// riscv
"aes32dsi" => "__builtin_riscv_aes32dsi",
@ -6119,14 +6127,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"sha512sum0r" => "__builtin_riscv_sha512sum0r",
"sha512sum1" => "__builtin_riscv_sha512sum1",
"sha512sum1r" => "__builtin_riscv_sha512sum1r",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
riscv(name)
riscv(name, full_name)
}
"s390" => {
#[allow(non_snake_case)]
fn s390(name: &str) -> &str {
fn s390(name: &str, full_name: &str) -> &'static str {
match name {
// s390
"bdepg" => "__builtin_s390_bdepg",
@ -6313,14 +6321,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"vupllf" => "__builtin_s390_vupllf",
"vupllg" => "__builtin_s390_vupllg",
"vupllh" => "__builtin_s390_vupllh",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
s390(name)
s390(name, full_name)
}
"ve" => {
#[allow(non_snake_case)]
fn ve(name: &str) -> &str {
fn ve(name: &str, full_name: &str) -> &'static str {
match name {
// ve
"vl.andm.MMM" => "__builtin_ve_vl_andm_MMM",
@ -7586,14 +7594,14 @@ fn map_arch_intrinsic(name: &str) -> &str {
"vl.vxor.vvvvl" => "__builtin_ve_vl_vxor_vvvvl",
"vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM",
"vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
ve(name)
ve(name, full_name)
}
"x86" => {
#[allow(non_snake_case)]
fn x86(name: &str) -> &str {
fn x86(name: &str, full_name: &str) -> &'static str {
match name {
// x86
"aadd32" => "__builtin_ia32_aadd32",
@ -10154,25 +10162,25 @@ fn map_arch_intrinsic(name: &str) -> &str {
"xresldtrk" => "__builtin_ia32_xresldtrk",
"xsusldtrk" => "__builtin_ia32_xsusldtrk",
"xtest" => "__builtin_ia32_xtest",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
x86(name)
x86(name, full_name)
}
"xcore" => {
#[allow(non_snake_case)]
fn xcore(name: &str) -> &str {
fn xcore(name: &str, full_name: &str) -> &'static str {
match name {
// xcore
"bitrev" => "__builtin_bitrev",
"getid" => "__builtin_getid",
"getps" => "__builtin_getps",
"setps" => "__builtin_setps",
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
xcore(name)
xcore(name, full_name)
}
_ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
_ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),
}
}

View file

@ -648,6 +648,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
new_args.push(handle);
args = new_args.into();
}
"__builtin_ia32_rdtscp" => {
let result = builder.current_func().new_local(None, builder.u32_type, "result");
let new_args = vec![result.get_address(None).to_rvalue()];
args = new_args.into();
}
_ => (),
}
} else {
@ -764,6 +769,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
new_args.swap(0, 1);
args = new_args.into();
}
"__builtin_ia32_dpps256" => {
let mut new_args = args.to_vec();
// NOTE: without this cast to u8 (and it needs to be a u8 to fix the issue), we
// would get the following error:
// the last argument must be an 8-bit immediate
new_args[2] = builder.context.new_cast(None, new_args[2], builder.cx.type_u8());
args = new_args.into();
}
_ => (),
}
}
@ -935,6 +948,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
);
return_value = result.to_rvalue();
}
"__builtin_ia32_rdtscp" => {
let field1 = builder.context.new_field(None, return_value.get_type(), "rdtscpField1");
let return2 = args[0].dereference(None).to_rvalue();
let field2 = builder.context.new_field(None, return2.get_type(), "rdtscpField2");
let struct_type =
builder.context.new_struct_type(None, "rdtscpResult", &[field1, field2]);
return_value = builder.context.new_struct_constructor(
None,
struct_type.as_type(),
None,
&[return_value, return2],
);
}
_ => (),
}
@ -1529,6 +1555,17 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8",
"llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8",
"llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8",
"llvm.x86.avx512.uitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtuw2ph128_mask",
"llvm.x86.avx512.uitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtuw2ph256_mask",
"llvm.x86.avx512.uitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtuw2ph512_mask_round",
"llvm.x86.avx512.uitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtudq2ph256_mask",
"llvm.x86.avx512.uitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtudq2ph512_mask_round",
"llvm.x86.avx512.uitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtuqq2ph512_mask_round",
"llvm.x86.avx512.uitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtuqq2pd512_mask",
"llvm.x86.avx512.uitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtuqq2pd128_mask",
"llvm.x86.avx512.uitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtuqq2pd256_mask",
"llvm.x86.avx512.uitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtuqq2ps512_mask",
"llvm.x86.avx512.uitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtuqq2ps256_mask",
// TODO: support the tile builtins:
"llvm.x86.ldtilecfg" => "__builtin_trap",

View file

@ -114,7 +114,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
}
sym::copysignf32 => "copysignf",
sym::copysignf64 => "copysign",
sym::copysignf128 => "copysignl",
sym::floorf32 => "floorf",
sym::floorf64 => "floor",
sym::ceilf32 => "ceilf",
@ -238,6 +237,7 @@ fn get_simple_function_f128_2args<'gcc, 'tcx>(
let func_name = match name {
sym::maxnumf128 => "fmaxf128",
sym::minnumf128 => "fminf128",
sym::copysignf128 => "copysignf128",
_ => return None,
};
Some(cx.context.new_function(
@ -261,6 +261,7 @@ fn f16_builtin<'gcc, 'tcx>(
let f32_type = cx.type_f32();
let builtin_name = match name {
sym::ceilf16 => "__builtin_ceilf",
sym::copysignf16 => "__builtin_copysignf",
sym::floorf16 => "__builtin_floorf",
sym::fmaf16 => "fmaf",
sym::maxnumf16 => "__builtin_fmaxf",
@ -330,6 +331,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
)
}
sym::ceilf16
| sym::copysignf16
| sym::floorf16
| sym::fmaf16
| sym::maxnumf16

View file

@ -176,14 +176,14 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
out.write("// DO NOT EDIT IT!\n")
out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n")
out.write("fn map_arch_intrinsic(name:&str)->&str{\n")
out.write('let Some(name) = name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n")
out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n')
out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n')
out.write("match arch {\n")
for arch in archs:
if len(intrinsics[arch]) == 0:
continue
out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str) -> &str {{ match name {{".format(arch,arch))
out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch,arch))
intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
out.write(' // {}\n'.format(arch))
for entry in intrinsics[arch]:
@ -196,9 +196,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1]))
else:
out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1]))
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
out.write("}} }} {}(name) }}\n,".format(arch))
out.write(' _ => unimplemented!("***** unsupported LLVM architecture {}", name),\n')
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n')
out.write("}} }} {}(name,full_name) }}\n,".format(arch))
out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n')
out.write("}\n}")
subprocess.call(["rustfmt", output_file])
print("Done!")

View file

@ -268,7 +268,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
}
}
Scalar::Ptr(ptr, _size) => {
let (prov, offset) = ptr.into_parts();
let (prov, offset) = ptr.prov_and_relative_offset();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let base_addr = match global_alloc {
GlobalAlloc::Memory(alloc) => {

View file

@ -124,6 +124,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
AttributeKind::LinkSection { name, .. } => {
codegen_fn_attrs.link_section = Some(*name)
}
AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
@ -253,16 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
}
sym::link_section => {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!("illegal null byte in link_section value: `{val}`");
tcx.dcx().span_err(attr.span(), msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
}
}
sym::link_ordinal => {
link_ordinal_span = Some(attr.span());
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {

View file

@ -1,7 +1,7 @@
use rustc_abi::WrappingRange;
use rustc_middle::bug;
use rustc_middle::mir::SourceInfo;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::sym;
@ -98,6 +98,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
discr.to_atomic_ordering()
};
if args.is_empty() {
match name {
sym::abort
| sym::unreachable
| sym::cold_path
| sym::breakpoint
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid
| sym::assert_inhabited
| sym::ub_checks
| sym::contract_checks
| sym::atomic_fence
| sym::atomic_singlethreadfence
| sym::caller_location => {}
_ => {
span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic
");
}
}
}
let llval = match name {
sym::abort => {
bx.abort();
@ -150,10 +171,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
value
}
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap();
OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx)
}
sym::arith_offset => {
let ty = fn_args.type_at(0);
let layout = bx.layout_of(ty);

View file

@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let destination_block = target.unwrap();
bb.statements.push(mir::Statement {
source_info: bb.terminator().source_info,
kind: mir::StatementKind::Assign(Box::new((
bb.statements.push(mir::Statement::new(
bb.terminator().source_info,
mir::StatementKind::Assign(Box::new((
*destination,
mir::Rvalue::Use(mir::Operand::Copy(
arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx),
)),
))),
});
));
bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block };
}

View file

@ -263,9 +263,6 @@ const_eval_non_const_try_block_from_output =
const_eval_not_enough_caller_args =
calling a function with fewer arguments than it requires
const_eval_nullary_intrinsic_fail =
could not evaluate nullary intrinsic
const_eval_offset_from_different_allocations =
`{$name}` called on two different pointers that are not both derived from the same allocation
const_eval_offset_from_out_of_bounds =

View file

@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment;
use crate::interpret::{
CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind,
InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc,
eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust,
intern_const_alloc_recursive, interp_ok, throw_exhaust,
};
use crate::{CTRL_C_RECEIVED, errors};
@ -209,9 +209,9 @@ pub(super) fn op_to_const<'tcx>(
match immediate {
Left(ref mplace) => {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (prov, offset) = mplace.ptr().into_parts();
let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id();
let (prov, offset) =
mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset();
let alloc_id = prov.alloc_id();
ConstValue::Indirect { alloc_id, offset }
}
// see comment on `let force_as_immediate` above
@ -232,9 +232,10 @@ pub(super) fn op_to_const<'tcx>(
imm.layout.ty,
);
let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts();
let alloc_id = prov.expect(msg).alloc_id();
let ptr = a.to_pointer(ecx).expect(msg);
let (prov, offset) =
ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset();
let alloc_id = prov.alloc_id();
let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
assert!(offset == abi::Size::ZERO, "{}", msg);
let meta = b.to_target_usize(ecx).expect(msg);
@ -280,34 +281,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
let ty = key.value.instance.ty(tcx, key.typing_env);
let ty::FnDef(_, args) = ty.kind() else {
bug!("intrinsic with type {:?}", ty);
};
return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err(
|error| {
let span = tcx.def_span(def_id);
// FIXME(oli-obk): why don't we have any tests for this code path?
super::report(
tcx,
error.into_kind(),
span,
|| (span, vec![]),
|diag, span, _| {
diag.span_label(
span,
crate::fluent_generated::const_eval_nullary_intrinsic_fail,
);
},
)
},
);
}
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
}

View file

@ -574,7 +574,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
if addr != 0 {
diag.arg(
"pointer",
Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
Pointer::<Option<CtfeProvenance>>::without_provenance(addr).to_string(),
);
}

View file

@ -6,10 +6,9 @@ use std::assert_matches::assert_matches;
use rustc_abi::Size;
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement};
use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_middle::{bug, ty};
use rustc_span::{Symbol, sym};
use tracing::trace;
@ -17,8 +16,8 @@ use tracing::trace;
use super::memory::MemoryKind;
use super::util::ensure_monomorphic_enough;
use super::{
Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine,
OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy,
PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
};
use crate::fluent_generated as fluent;
@ -30,73 +29,6 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
tcx.mk_const_alloc(alloc)
}
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
pub(crate) fn eval_nullary_intrinsic<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
def_id: DefId,
args: GenericArgsRef<'tcx>,
) -> InterpResult<'tcx, ConstValue<'tcx>> {
let tp_ty = args.type_at(0);
let name = tcx.item_name(def_id);
interp_ok(match name {
sym::type_name => {
ensure_monomorphic_enough(tcx, tp_ty)?;
let alloc = alloc_type_name(tcx, tp_ty);
ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() }
}
sym::needs_drop => {
ensure_monomorphic_enough(tcx, tp_ty)?;
ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env))
}
sym::type_id => {
ensure_monomorphic_enough(tcx, tp_ty)?;
ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128())
}
sym::variant_count => match match tp_ty.kind() {
// Pattern types have the same number of variants as their base type.
// Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited.
// And `Result<(), !>` still has two variants according to `variant_count`.
ty::Pat(base, _) => *base,
_ => tp_ty,
}
.kind()
{
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx),
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
ty::Pat(..) => unreachable!(),
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::UnsafeBinder(_)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
},
other => bug!("`{}` is not a zero arg intrinsic", other),
})
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Returns `true` if emulation happened.
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
@ -110,8 +42,77 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx, bool> {
let instance_args = instance.args;
let intrinsic_name = self.tcx.item_name(instance.def_id());
let tcx = self.tcx.tcx;
match intrinsic_name {
sym::type_name => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
let alloc = alloc_type_name(tcx, tp_ty);
let val = ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() };
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::needs_drop => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env));
let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::type_id => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128());
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::variant_count => {
let tp_ty = instance.args.type_at(0);
let ty = match tp_ty.kind() {
// Pattern types have the same number of variants as their base type.
// Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited.
// And `Result<(), !>` still has two variants according to `variant_count`.
ty::Pat(base, _) => *base,
_ => tp_ty,
};
let val = match ty.kind() {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
ty::Adt(adt, _) => {
ConstValue::from_target_usize(adt.variants().len() as u64, &tcx)
}
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
ty::Pat(..) => unreachable!(),
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::UnsafeBinder(_)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
};
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::caller_location => {
let span = self.find_closest_untracked_caller_location();
let val = self.tcx.span_as_caller_location(span);
@ -137,21 +138,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_scalar(Scalar::from_target_usize(result, self), dest)?;
}
sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
let gid = GlobalId { instance, promoted: None };
let ty = self
.tcx
.fn_sig(instance.def_id())
.instantiate(self.tcx.tcx, instance.args)
.output()
.no_bound_vars()
.unwrap();
let val = self
.ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?;
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::fadd_algebraic
| sym::fsub_algebraic
| sym::fmul_algebraic

View file

@ -747,7 +747,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
// Allow these casts, but make the pointer not dereferenceable.
// (I.e., they behave like transmutation.)
// This is correct because no pointers can ever be exposed in compile-time evaluation.
interp_ok(Pointer::from_addr_invalid(addr))
interp_ok(Pointer::without_provenance(addr))
}
#[inline(always)]
@ -756,8 +756,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
ptr: Pointer<CtfeProvenance>,
_size: i64,
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (prov, offset) = ptr.into_parts();
let (prov, offset) = ptr.prov_and_relative_offset();
Some((prov.alloc_id(), offset, prov.immutable()))
}

View file

@ -1596,7 +1596,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)),
None => {
assert!(M::Provenance::OFFSET_IS_ADDR);
let (_, addr) = ptr.into_parts();
// Offset is absolute, as we just asserted.
let (_, addr) = ptr.into_raw_parts();
Err(addr.bytes())
}
},

View file

@ -29,7 +29,6 @@ pub use self::intern::{
HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop,
intern_const_alloc_recursive,
};
pub(crate) use self::intrinsics::eval_nullary_intrinsic;
pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
use self::operand::Operand;

View file

@ -118,7 +118,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self {
assert!(layout.is_zst());
let align = layout.align.abi;
let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address
let ptr = Pointer::without_provenance(align.bytes()); // no provenance, absolute address
MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout }
}

View file

@ -518,7 +518,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
ptr_kind,
// FIXME this says "null pointer" when null but we need translate
pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i))
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
},
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
ptr_kind
@ -868,7 +868,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
fn add_data_range(&mut self, ptr: Pointer<Option<M::Provenance>>, size: Size) {
if let Some(data_bytes) = self.data_bytes.as_mut() {
// We only have to store the offset, the rest is the same for all pointers here.
let (_prov, offset) = ptr.into_parts();
// The logic is agnostic to wether the offset is relative or absolute as long as
// it is consistent.
let (_prov, offset) = ptr.into_raw_parts();
// Add this.
data_bytes.add_range(offset, size);
};
@ -894,7 +896,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
.as_mplace_or_imm()
.expect_left("place must be in memory")
.ptr();
let (_prov, offset) = ptr.into_parts();
let (_prov, offset) = ptr.into_raw_parts();
offset
}
@ -903,7 +905,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
// Our value must be in memory, otherwise we would not have set up `data_bytes`.
let mplace = self.ecx.force_allocation(place)?;
// Determine starting offset and size.
let (_prov, start_offset) = mplace.ptr().into_parts();
let (_prov, start_offset) = mplace.ptr().into_raw_parts();
let (size, _align) = self
.ecx
.size_and_align_of_val(&mplace)?

View file

@ -1112,7 +1112,9 @@ fn get_backend_from_raw_matches(
matches: &Matches,
) -> Box<dyn CodegenBackend> {
let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
let backend_name = debug_flags
.iter()
.find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend=")));
let target = parse_target_triple(early_dcx, matches);
let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
let target = config::build_target_config(early_dcx, &target, sysroot.path());

View file

@ -278,8 +278,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
/// fall back to subtyping (`unify_and`).
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
assert!(self.shallow_resolve(b) == b);
debug_assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
if b.is_ty_var() {
// Two unresolved type variables: create a `Coerce` predicate.
@ -323,6 +323,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
mutbl_b: hir::Mutability,
) -> CoerceResult<'tcx> {
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
// If we have a parameter of type `&M T_a` and the value
// provided is `expr`, we will be adding an implicit borrow,
@ -514,10 +516,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
///
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
#[instrument(skip(self), level = "debug")]
fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
source = self.shallow_resolve(source);
target = self.shallow_resolve(target);
fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!(?source, ?target);
debug_assert!(self.shallow_resolve(source) == source);
debug_assert!(self.shallow_resolve(target) == target);
// We don't apply any coercions incase either the source or target
// aren't sufficiently well known but tend to instead just equate
@ -531,6 +533,54 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(TypeError::Mismatch);
}
// This is an optimization because coercion is one of the most common
// operations that we do in typeck, since it happens at every assignment
// and call arg (among other positions).
//
// These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
// That's because these are built-in types for which a core-provided impl
// doesn't exist, and for which a user-written impl is invalid.
//
// This is technically incomplete when users write impossible bounds like
// `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
// and coercion is allowed to be incomplete. The only case where this matters
// is impossible bounds.
//
// Note that some of these types implement `LHS: Unsize<RHS>`, but they
// do not implement *`CoerceUnsized`* which is the root obligation of the
// check below.
match target.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Str
| ty::Array(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_, _)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _)
| ty::Never
| ty::Tuple(_) => return Err(TypeError::Mismatch),
_ => {}
}
// Additionally, we ignore `&str -> &str` coercions, which happen very
// commonly since strings are one of the most used argument types in Rust,
// we do coercions when type checking call expressions.
if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind()
&& source_pointee.is_str()
&& let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind()
&& target_pointee.is_str()
{
return Err(TypeError::Mismatch);
}
let traits =
(self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {
@ -800,6 +850,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
/// - `Pin<Box<T>>` as `Pin<&mut T>`
#[instrument(skip(self), level = "trace")]
fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
// We need to make sure the two types are compatible for coercion.
// Then we will build a ReborrowPin adjustment and return that as an InferOk.
@ -848,6 +901,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
b: Ty<'tcx>,
adjustment: Option<Adjust>,
) -> CoerceResult<'tcx> {
debug_assert!(self.shallow_resolve(b) == b);
self.commit_if_ok(|snapshot| {
let outer_universe = self.infcx.universe();
@ -888,24 +943,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
//! into a closure or a `proc`.
//!
let b = self.shallow_resolve(b);
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
debug_assert!(self.shallow_resolve(b) == b);
self.coerce_from_safe_fn(fn_ty_a, b, None)
}
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
//! into a closure or a `proc`.
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
let b = self.shallow_resolve(b);
let InferOk { value: b, mut obligations } =
self.at(&self.cause, self.param_env).normalize(b);
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.kind() {
ty::FnPtr(_, b_hdr) => {
@ -955,6 +1005,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
}
/// Attempts to coerce from the type of a non-capturing closure
/// into a function pointer.
fn coerce_closure_to_fn(
&self,
a: Ty<'tcx>,
@ -962,11 +1014,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
args_a: GenericArgsRef<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a non-capturing closure
//! into a function pointer.
//!
let b = self.shallow_resolve(b);
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
match b.kind() {
// At this point we haven't done capture analysis, which means
@ -1010,6 +1059,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
mutbl_b: hir::Mutability,
) -> CoerceResult<'tcx> {
debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b);
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);
let (is_ref, mt_a) = match *a.kind() {
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),

View file

@ -3055,7 +3055,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn note_unmet_impls_on_type(
&self,
err: &mut Diag<'_>,
errors: Vec<FulfillmentError<'tcx>>,
errors: &[FulfillmentError<'tcx>],
suggest_derive: bool,
) {
let preds: Vec<_> = errors

View file

@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lhs_expr.span,
format!("cannot use `{}` on type `{}`", s, lhs_ty_str),
);
self.note_unmet_impls_on_type(&mut err, errors, false);
self.note_unmet_impls_on_type(&mut err, &errors, false);
(err, None)
}
Op::BinOp(bin_op) => {
@ -382,7 +382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(rhs_expr.span, rhs_ty_str);
}
let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty);
self.note_unmet_impls_on_type(&mut err, errors, suggest_derive);
self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive);
(err, output_def_id)
}
};
@ -582,22 +582,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
} else if lhs_ty.has_non_region_param() {
// Look for a TraitPredicate in the Fulfillment errors,
// and use it to generate a suggestion.
//
// Note that lookup_op_method must be called again but
// with a specific rhs_ty instead of a placeholder so
// the resulting predicate generates a more specific
// suggestion for the user.
let errors = self
.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty)),
lang_item_for_binop(self.tcx, op),
op.span(),
expected,
)
.unwrap_err();
if !errors.is_empty() {
for error in errors {
if let Some(trait_pred) =
@ -946,7 +930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {}
ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {}
_ => {
self.note_unmet_impls_on_type(&mut err, errors, true);
self.note_unmet_impls_on_type(&mut err, &errors, true);
}
}
}

View file

@ -110,17 +110,16 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r.kind() {
ty::ReBound(..) => {
// leave bound regions alone
r
}
// Leave bound regions alone, since they affect selection via the leak check.
ty::ReBound(..) => r,
// Leave error regions alone, since they affect selection b/c of incompleteness.
ty::ReError(_) => r,
ty::ReEarlyParam(..)
| ty::ReLateParam(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
| ty::ReStatic
| ty::ReError(_)
| ty::ReErased => self.cx().lifetimes.re_erased,
}
}

View file

@ -298,6 +298,16 @@ fn configure_and_expand(
fn print_macro_stats(ecx: &ExtCtxt<'_>) {
use std::fmt::Write;
let crate_name = ecx.ecfg.crate_name.as_str();
let crate_name = if crate_name == "build_script_build" {
// This is a build script. Get the package name from the environment.
let pkg_name =
std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "<unknown crate>".to_string());
format!("{pkg_name} build script")
} else {
crate_name.to_string()
};
// No instability because we immediately sort the produced vector.
#[allow(rustc::potential_query_instability)]
let mut macro_stats: Vec<_> = ecx
@ -327,7 +337,7 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) {
// non-interleaving, though.
let mut s = String::new();
_ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
_ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name);
_ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", crate_name);
_ = writeln!(
s,
"{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
@ -341,20 +351,30 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) {
}
for (bytes, lines, uses, name, kind) in macro_stats {
let mut name = ExpnKind::Macro(kind, *name).descr();
let uses_with_underscores = thousands::usize_with_underscores(uses);
let avg_lines = lines as f64 / uses as f64;
let avg_bytes = bytes as f64 / uses as f64;
if name.len() >= name_w {
// If the name is long, print it on a line by itself, then
// set the name to empty and print things normally, to show the
// stats on the next line.
// Ensure the "Macro Name" and "Uses" columns are as compact as possible.
let mut uses_w = uses_w;
if name.len() + uses_with_underscores.len() >= name_w + uses_w {
// The name would abut or overlap the uses value. Print the name
// on a line by itself, then set the name to empty and print things
// normally, to show the stats on the next line.
_ = writeln!(s, "{prefix} {:<name_w$}", name);
name = String::new();
}
} else if name.len() >= name_w {
// The name won't abut or overlap with the uses value, but it does
// overlap with the empty part of the uses column. Shrink the width
// of the uses column to account for the excess name length.
uses_w = uses_with_underscores.len() + 1
};
_ = writeln!(
s,
"{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
name,
thousands::usize_with_underscores(uses),
uses_with_underscores,
thousands::usize_with_underscores(lines),
thousands::f64p1_with_underscores(avg_lines),
thousands::usize_with_underscores(bytes),

View file

@ -168,8 +168,9 @@ impl<'tcx> ConstValue<'tcx> {
return Some(&[]);
}
// Non-empty slice, must have memory. We know this is a relative pointer.
let (inner_prov, offset) = ptr.into_parts();
let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory();
let (inner_prov, offset) =
ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset();
let data = tcx.global_alloc(inner_prov.alloc_id()).unwrap_memory();
(data, offset.bytes(), offset.bytes() + len)
}
};

View file

@ -526,7 +526,7 @@ impl Allocation {
let ptr_bytes = &mut bytes[idx..idx + ptr_size];
let bits = read_target_uint(endian, ptr_bytes).unwrap();
let (ptr_prov, ptr_offset) =
adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts();
write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
new_provenance.push((offset, ptr_prov));
}
@ -769,7 +769,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
// as-is into memory. This also double-checks that `val.size()` matches `range.size`.
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
Right(ptr) => {
let (provenance, offset) = ptr.into_parts();
let (provenance, offset) = ptr.into_raw_parts();
(u128::from(offset.bytes()), Some(provenance))
}
Left(data) => (data, None),

View file

@ -288,7 +288,7 @@ impl From<CtfeProvenance> for Pointer {
impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> {
#[inline(always)]
fn from(ptr: Pointer<Prov>) -> Self {
let (prov, offset) = ptr.into_parts();
let (prov, offset) = ptr.into_raw_parts();
Pointer::new(Some(prov), offset)
}
}
@ -314,19 +314,17 @@ impl<Prov> Pointer<Option<Prov>> {
assert!(Prov::OFFSET_IS_ADDR);
self.offset
}
}
impl<Prov> Pointer<Option<Prov>> {
/// Creates a pointer to the given address, with invalid provenance (i.e., cannot be used for
/// any memory access).
#[inline(always)]
pub fn from_addr_invalid(addr: u64) -> Self {
pub fn without_provenance(addr: u64) -> Self {
Pointer { provenance: None, offset: Size::from_bytes(addr) }
}
#[inline(always)]
pub fn null() -> Self {
Pointer::from_addr_invalid(0)
Pointer::without_provenance(0)
}
}
@ -336,11 +334,11 @@ impl<Prov> Pointer<Prov> {
Pointer { provenance, offset }
}
/// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`!
/// This function must only be used in the implementation of `Machine::ptr_get_alloc`,
/// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`.
/// Obtain the constituents of this pointer. Note that the meaning of the offset depends on the
/// type `Prov`! This is a low-level function that should only be used when absolutely
/// necessary. Prefer `prov_and_relative_offset` if possible.
#[inline(always)]
pub fn into_parts(self) -> (Prov, Size) {
pub fn into_raw_parts(self) -> (Prov, Size) {
(self.provenance, self.offset)
}
@ -361,3 +359,12 @@ impl<Prov> Pointer<Prov> {
self.wrapping_offset(Size::from_bytes(i as u64), cx)
}
}
impl Pointer<CtfeProvenance> {
/// Return the provenance and relative offset stored in this pointer. Safer alternative to
/// `into_raw_parts` since the type ensures that the offset is indeed relative.
#[inline(always)]
pub fn prov_and_relative_offset(self) -> (CtfeProvenance, Size) {
(self.provenance, self.offset)
}
}

View file

@ -109,7 +109,7 @@ impl<Prov> Scalar<Prov> {
/// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a
/// plain integer / "invalid" pointer).
pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
match ptr.into_parts() {
match ptr.into_raw_parts() {
(Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx),
(None, offset) => {
Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap())
@ -276,7 +276,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
Right(ptr) => interp_ok(ptr.into()),
Left(bits) => {
let addr = u64::try_from(bits).unwrap();
interp_ok(Pointer::from_addr_invalid(addr))
interp_ok(Pointer::without_provenance(addr))
}
}
}
@ -299,7 +299,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
} else {
// We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
let (prov, offset) = ptr.into_parts();
let (prov, offset) = ptr.into_raw_parts();
// Because `OFFSET_IS_ADDR == false`, this unwrap can never fail.
Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz))
}

View file

@ -1359,7 +1359,15 @@ pub struct BasicBlockData<'tcx> {
impl<'tcx> BasicBlockData<'tcx> {
pub fn new(terminator: Option<Terminator<'tcx>>, is_cleanup: bool) -> BasicBlockData<'tcx> {
BasicBlockData { statements: vec![], terminator, is_cleanup }
BasicBlockData::new_stmts(Vec::new(), terminator, is_cleanup)
}
pub fn new_stmts(
statements: Vec<Statement<'tcx>>,
terminator: Option<Terminator<'tcx>>,
is_cleanup: bool,
) -> BasicBlockData<'tcx> {
BasicBlockData { statements, terminator, is_cleanup }
}
/// Accessor for terminator.

View file

@ -16,12 +16,16 @@ pub struct Statement<'tcx> {
pub kind: StatementKind<'tcx>,
}
impl Statement<'_> {
impl<'tcx> Statement<'tcx> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// invalidating statement indices in `Location`s.
pub fn make_nop(&mut self) {
self.kind = StatementKind::Nop
}
pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
Statement { source_info, kind }
}
}
impl<'tcx> StatementKind<'tcx> {

View file

@ -1755,7 +1755,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
) -> Result<(), PrintError> {
define_scoped_cx!(self);
let (prov, offset) = ptr.into_parts();
let (prov, offset) = ptr.prov_and_relative_offset();
match ty.kind() {
// Byte strings (&[u8; N])
ty::Ref(_, inner, _) => {

View file

@ -42,7 +42,7 @@ impl<'tcx> CFG<'tcx> {
) {
self.push(
block,
Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) },
Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))),
);
}
@ -88,7 +88,7 @@ impl<'tcx> CFG<'tcx> {
place: Place<'tcx>,
) {
let kind = StatementKind::FakeRead(Box::new((cause, place)));
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}
@ -99,7 +99,7 @@ impl<'tcx> CFG<'tcx> {
place: Place<'tcx>,
) {
let kind = StatementKind::PlaceMention(Box::new(place));
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}
@ -110,7 +110,7 @@ impl<'tcx> CFG<'tcx> {
/// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}

View file

@ -61,10 +61,10 @@ impl BlockMarkerGen {
block: BasicBlock,
) -> BlockMarkerId {
let id = self.next_block_marker_id();
let marker_statement = mir::Statement {
let marker_statement = mir::Statement::new(
source_info,
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
};
mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
);
cfg.push(block, marker_statement);
id

View file

@ -315,10 +315,8 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
let stmt = self.statement_as_expr(*stmt_id)?;
let span = self.thir[stmt].span;
let statement = self.parse_statement(stmt)?;
data.statements.push(Statement {
source_info: SourceInfo { span, scope: self.source_scope },
kind: statement,
});
data.statements
.push(Statement::new(SourceInfo { span, scope: self.source_scope }, statement));
}
let Some(trailing) = block.expr else { return Err(self.expr_error(expr_id, "terminator")) };

View file

@ -489,16 +489,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place = place_builder.to_place(this);
this.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((
place,
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
},
),
);
}
block.and(place_builder)
@ -518,16 +518,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
});
this.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((
Place::from(temp),
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
},
),
);
}
block.and(PlaceBuilder::from(temp))

View file

@ -175,10 +175,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// and therefore is not considered during coroutine auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span));
this.cfg.push(
block,
Statement { source_info, kind: StatementKind::StorageLive(result) },
);
this.cfg
.push(block, Statement::new(source_info, StatementKind::StorageLive(result)));
if let Some(scope) = scope.temp_lifetime {
// schedule a shallow free of that memory, lest we unwind:
this.schedule_drop_storage_and_value(expr_span, scope, result);
@ -278,12 +276,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};
this.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::Assume(Operand::Move(assert_place)),
)),
},
StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
Operand::Move(assert_place),
))),
),
);
}
@ -789,7 +787,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let source_info = this.source_info(upvar_span);
let temp = this.local_decls.push(LocalDecl::new(upvar_ty, upvar_span));
this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp)));
let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));

View file

@ -102,8 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block]
&& expr_ty.is_never() => {}
_ => {
this.cfg
.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp)));
// In constants, `temp_lifetime` is `None` for temporaries that
// live for the `'static` lifetime. Thus we do not drop these

View file

@ -646,9 +646,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let base = self.canonical_user_type_annotations.push(annotation.clone());
self.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
// We always use invariant as the variance here. This is because the
// variance field from the ascription refers to the variance to use
@ -666,7 +666,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// `<expr>`.
ty::Invariant,
),
},
),
);
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> Place<'tcx> {
let local_id = self.var_local_id(var, for_guard);
let source_info = self.source_info(span);
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
self.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(local_id)));
// Although there is almost always scope for given variable in corner cases
// like #92893 we might get variable with no scope.
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id)
@ -2578,16 +2578,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let base = self.canonical_user_type_annotations.push(ascription.annotation);
self.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::AscribeUserType(
StatementKind::AscribeUserType(
Box::new((
ascription.source,
UserTypeProjection { base, projs: Vec::new() },
)),
ascription.variance,
),
},
),
);
}
}

View file

@ -431,13 +431,13 @@ impl DropTree {
cfg.terminate(block, drop_node.data.source_info, terminator);
}
DropKind::ForLint => {
let stmt = Statement {
source_info: drop_node.data.source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
let stmt = Statement::new(
drop_node.data.source_info,
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(drop_node.data.local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
};
);
cfg.push(block, stmt);
let target = blocks[drop_node.next].unwrap();
if target != block {
@ -454,10 +454,10 @@ impl DropTree {
// Root nodes don't correspond to a drop.
DropKind::Storage if drop_idx == ROOT_NODE => {}
DropKind::Storage => {
let stmt = Statement {
source_info: drop_node.data.source_info,
kind: StatementKind::StorageDead(drop_node.data.local),
};
let stmt = Statement::new(
drop_node.data.source_info,
StatementKind::StorageDead(drop_node.data.local),
);
cfg.push(block, stmt);
let target = blocks[drop_node.next].unwrap();
if target != block {
@ -1124,13 +1124,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
DropKind::ForLint => {
self.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
},
),
);
}
DropKind::Storage => {
@ -1138,7 +1138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
assert!(local.index() > self.arg_count);
self.cfg.push(
block,
Statement { source_info, kind: StatementKind::StorageDead(local) },
Statement::new(source_info, StatementKind::StorageDead(local)),
);
}
}
@ -1880,13 +1880,13 @@ where
cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
},
),
);
}
DropKind::Storage => {
@ -1910,7 +1910,7 @@ where
}
// Only temps and vars need their storage dead.
assert!(local.index() > arg_count);
cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
cfg.push(block, Statement::new(source_info, StatementKind::StorageDead(local)));
}
}
}

View file

@ -17,13 +17,13 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
let mut blocks = IndexVec::new();
let mut block = |n, kind| {
let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop };
let nop = mir::Statement::new(source_info, mir::StatementKind::Nop);
blocks.push(mir::BasicBlockData {
statements: std::iter::repeat(&nop).cloned().take(n).collect(),
terminator: Some(mir::Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(mir::BasicBlockData::new_stmts(
std::iter::repeat(&nop).cloned().take(n).collect(),
Some(mir::Terminator { source_info, kind }),
false,
))
};
let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() };

View file

@ -44,11 +44,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
let cur_len = body.basic_blocks.len();
let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| {
let block = BasicBlockData {
statements: vec![],
let block = BasicBlockData::new(
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
is_cleanup,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
};
);
let idx = cur_len + new_blocks.len();
new_blocks.push(block);
BasicBlock::new(idx)

View file

@ -93,11 +93,11 @@ fn add_move_for_packed_drop<'tcx>(
let ty = place.ty(body, tcx).ty;
let temp = patch.new_temp(ty, source_info.span);
let storage_dead_block = patch.new_block(BasicBlockData {
statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
let storage_dead_block = patch.new_block(BasicBlockData::new_stmts(
vec![Statement::new(source_info, StatementKind::StorageDead(temp))],
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
is_cleanup,
});
));
patch.add_statement(loc, StatementKind::StorageLive(temp));
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));

View file

@ -81,9 +81,11 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
// Emit their retags.
basic_blocks[START_BLOCK].statements.splice(
0..0,
places.map(|(place, source_info)| Statement {
source_info,
kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
places.map(|(place, source_info)| {
Statement::new(
source_info,
StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
)
}),
);
}
@ -113,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
for (source_info, dest_place, dest_block) in returns {
basic_blocks[dest_block].statements.insert(
0,
Statement {
Statement::new(
source_info,
kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
},
StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
),
);
}
@ -174,10 +176,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
let source_info = block_data.statements[i].source_info;
block_data.statements.insert(
i + 1,
Statement {
source_info,
kind: StatementKind::Retag(retag_kind, Box::new(place)),
},
Statement::new(source_info, StatementKind::Retag(retag_kind, Box::new(place))),
);
}
}

View file

@ -51,22 +51,18 @@ fn insert_alignment_check<'tcx>(
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
stmts
.push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
// Get the alignment of the pointee
let alignment =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
stmts.push(Statement {
source_info,
kind: StatementKind::Assign(Box::new((alignment, rvalue))),
});
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((alignment, rvalue)))));
// Subtract 1 from the alignment to get the alignment mask
let alignment_mask =
@ -76,13 +72,13 @@ fn insert_alignment_check<'tcx>(
user_ty: None,
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
alignment_mask,
Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))),
))),
});
));
// If this target does not have reliable alignment, further limit the mask by anding it with
// the mask for the highest reliable alignment.
@ -99,31 +95,31 @@ fn insert_alignment_check<'tcx>(
tcx.types.usize,
),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
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();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
alignment_bits,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))),
),
))),
});
));
// Check if the alignment bits are all zero
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
@ -132,13 +128,13 @@ fn insert_alignment_check<'tcx>(
user_ty: None,
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_ok,
Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))),
))),
});
));
// Emit a check that asserts on the alignment and otherwise triggers a
// AssertKind::MisalignedPointerDereference.

View file

@ -41,13 +41,12 @@ fn insert_null_check<'tcx>(
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
stmts
.push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
let zero = Operand::Constant(Box::new(ConstOperand {
span: source_info.span,
@ -71,24 +70,24 @@ fn insert_null_check<'tcx>(
let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty);
let sizeof_pointee =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))),
});
StatementKind::Assign(Box::new((sizeof_pointee, rvalue))),
));
// Check that the pointee is not a ZST.
let is_pointee_not_zst =
local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_pointee_not_zst,
Rvalue::BinaryOp(
BinOp::Ne,
Box::new((Operand::Copy(sizeof_pointee), zero.clone())),
),
))),
});
));
// Pointer needs to be checked only if pointee is not a ZST.
Operand::Copy(is_pointee_not_zst)
@ -97,38 +96,38 @@ fn insert_null_check<'tcx>(
// Check whether the pointer is null.
let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_null,
Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))),
))),
});
));
// We want to throw an exception if the pointer is null and the pointee is not unconditionally
// allowed (which for all non-borrow place uses, is when the pointee is ZST).
let should_throw_exception =
local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
should_throw_exception,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(is_null), pointee_should_be_checked)),
),
))),
});
));
// The final condition whether this pointer usage is ok or not.
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_ok,
Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)),
))),
});
));
// Emit a PointerCheck that asserts on the condition and otherwise triggers
// a AssertKind::NullPointerDereference.

View file

@ -235,11 +235,11 @@ fn split_block(
let block_data = &mut basic_blocks[location.block];
// Drain every statement after this one and move the current terminator to a new basic block.
let new_block = BasicBlockData {
statements: block_data.statements.split_off(location.statement_index),
terminator: block_data.terminator.take(),
is_cleanup: block_data.is_cleanup,
};
let new_block = BasicBlockData::new_stmts(
block_data.statements.split_off(location.statement_index),
block_data.terminator.take(),
block_data.is_cleanup,
);
basic_blocks.push(new_block)
}

View file

@ -252,16 +252,16 @@ impl<'tcx> TransformVisitor<'tcx> {
}
};
let statements = vec![Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))),
let statements = vec![Statement::new(
source_info,
}];
StatementKind::Assign(Box::new((Place::return_place(), none_value))),
)];
body.basic_blocks_mut().push(BasicBlockData {
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
));
block
}
@ -342,10 +342,10 @@ impl<'tcx> TransformVisitor<'tcx> {
}
};
statements.push(Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
statements.push(Statement::new(
source_info,
});
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
));
}
// Create a Place referencing a coroutine struct field
@ -361,13 +361,13 @@ impl<'tcx> TransformVisitor<'tcx> {
// Create a statement which changes the discriminant
fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> {
let self_place = Place::from(SELF_ARG);
Statement {
Statement::new(
source_info,
kind: StatementKind::SetDiscriminant {
StatementKind::SetDiscriminant {
place: Box::new(self_place),
variant_index: state_disc,
},
}
)
}
// Create a statement which reads the discriminant into a temporary
@ -377,10 +377,10 @@ impl<'tcx> TransformVisitor<'tcx> {
let temp = Place::from(local_decls_len);
let self_place = Place::from(SELF_ARG);
let assign = Statement {
source_info: SourceInfo::outermost(body.span),
kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
};
let assign = Statement::new(
SourceInfo::outermost(body.span),
StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
);
(assign, temp)
}
}
@ -450,7 +450,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
&& !self.always_live_locals.contains(l);
if needs_storage_dead {
data.statements
.push(Statement { source_info, kind: StatementKind::StorageDead(l) });
.push(Statement::new(source_info, StatementKind::StorageDead(l)));
}
}
@ -596,10 +596,8 @@ fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local
let local = arg.node.place().unwrap().local;
let arg = Rvalue::Use(arg.node);
let assign = Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((destination, arg))),
};
let assign =
Statement::new(terminator.source_info, StatementKind::Assign(Box::new((destination, arg))));
bb_data.statements.push(assign);
bb_data.terminator = Some(Terminator {
source_info: terminator.source_info,
@ -1075,11 +1073,11 @@ fn insert_switch<'tcx>(
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().raw.insert(
0,
BasicBlockData {
statements: vec![assign],
terminator: Some(Terminator { source_info, kind: switch }),
is_cleanup: false,
},
BasicBlockData::new_stmts(
vec![assign],
Some(Terminator { source_info, kind: switch }),
false,
),
);
for b in body.basic_blocks_mut().iter_mut() {
@ -1089,11 +1087,7 @@ fn insert_switch<'tcx>(
fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
body.basic_blocks_mut().push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
}
fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> {
@ -1109,19 +1103,16 @@ fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) ->
Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::from_usize(0), args, None, None)),
IndexVec::from_raw(vec![val]),
);
Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), ready_val))),
source_info,
}
Statement::new(source_info, StatementKind::Assign(Box::new((Place::return_place(), ready_val))))
}
fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> BasicBlock {
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData {
statements: [return_poll_ready_assign(tcx, source_info)].to_vec(),
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
})
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[return_poll_ready_assign(tcx, source_info)].to_vec(),
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
))
}
fn insert_panic_block<'tcx>(
@ -1205,13 +1196,11 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>(
body: &mut Body<'tcx>,
) {
let source_info = SourceInfo::outermost(body.span);
let poison_block = body.basic_blocks_mut().push(BasicBlockData {
statements: vec![
transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info),
],
terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }),
is_cleanup: true,
});
let poison_block = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
vec![transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info)],
Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }),
true,
));
for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
let source_info = block.terminator().source_info;
@ -1345,32 +1334,28 @@ fn create_cases<'tcx>(
&& !transform.remap.contains(l)
&& !transform.always_live_locals.contains(l);
if needs_storage_live {
statements
.push(Statement { source_info, kind: StatementKind::StorageLive(l) });
statements.push(Statement::new(source_info, StatementKind::StorageLive(l)));
}
}
if operation == Operation::Resume {
// Move the resume argument to the destination place of the `Yield` terminator
let resume_arg = CTX_ARG;
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
point.resume_arg,
Rvalue::Use(Operand::Move(resume_arg.into())),
))),
});
));
}
// Then jump to the real target
let block = body.basic_blocks_mut().push(BasicBlockData {
let block = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator {
source_info,
kind: TerminatorKind::Goto { target },
}),
is_cleanup: false,
});
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
false,
));
(point.state, block)
})
@ -1540,13 +1525,13 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements;
stmts.insert(
0,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
old_resume_local.into(),
Rvalue::Use(Operand::Move(resume_local.into())),
))),
},
),
);
let always_live_locals = always_storage_live_locals(body);

View file

@ -87,12 +87,11 @@ fn build_pin_fut<'tcx>(
const_: Const::zero_sized(pin_fut_new_unchecked_fn),
}));
let storage_live =
Statement { source_info, kind: StatementKind::StorageLive(fut_pin_place.local) };
let storage_live = Statement::new(source_info, StatementKind::StorageLive(fut_pin_place.local));
let fut_ref_assign = Statement {
let fut_ref_assign = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
fut_ref_place,
Rvalue::Ref(
tcx.lifetimes.re_erased,
@ -100,12 +99,12 @@ fn build_pin_fut<'tcx>(
fut_place,
),
))),
};
);
// call Pin<FutTy>::new_unchecked(&mut fut)
let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData {
statements: [storage_live, fut_ref_assign].to_vec(),
terminator: Some(Terminator {
let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[storage_live, fut_ref_assign].to_vec(),
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: pin_fut_new_unchecked_fn,
@ -117,8 +116,8 @@ fn build_pin_fut<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
false,
));
(pin_fut_bb, fut_pin_place)
}
@ -156,19 +155,15 @@ fn build_poll_switch<'tcx>(
let source_info = SourceInfo::outermost(body.span);
let poll_discr_place =
Place::from(body.local_decls.push(LocalDecl::new(poll_discr_ty, source_info.span)));
let discr_assign = Statement {
let discr_assign = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
poll_discr_place,
Rvalue::Discriminant(*poll_unit_place),
))),
};
let storage_dead =
Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) };
StatementKind::Assign(Box::new((poll_discr_place, Rvalue::Discriminant(*poll_unit_place)))),
);
let storage_dead = Statement::new(source_info, StatementKind::StorageDead(fut_pin_place.local));
let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable);
body.basic_blocks_mut().push(BasicBlockData {
statements: [storage_dead, discr_assign].to_vec(),
terminator: Some(Terminator {
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[storage_dead, discr_assign].to_vec(),
Some(Terminator {
source_info,
kind: TerminatorKind::SwitchInt {
discr: Operand::Move(poll_discr_place),
@ -179,8 +174,8 @@ fn build_poll_switch<'tcx>(
),
},
}),
is_cleanup: false,
})
false,
))
}
// Gather blocks, reachable through 'drop' targets of Yield and Drop terminators (chained)
@ -330,10 +325,10 @@ pub(super) fn expand_async_drops<'tcx>(
let context_ref_place =
Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)));
let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG)));
body[bb].statements.push(Statement {
body[bb].statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((context_ref_place, arg))),
});
StatementKind::Assign(Box::new((context_ref_place, arg))),
));
let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
let (pin_bb, fut_pin_place) =
build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue);
@ -551,11 +546,8 @@ pub(super) fn insert_clean_drop<'tcx>(
};
// Create a block to destroy an unresumed coroutines. This can only destroy upvars.
body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator { source_info, kind: term }),
is_cleanup: false,
})
body.basic_blocks_mut()
.push(BasicBlockData::new(Some(Terminator { source_info, kind: term }), false))
}
pub(super) fn create_coroutine_drop_shim<'tcx>(
@ -734,11 +726,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>(
body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info);
// call coroutine_drop()
let call_bb = body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: None,
is_cleanup: false,
});
let call_bb = body.basic_blocks_mut().push(BasicBlockData::new(None, false));
// return Poll::Ready()
let ret_bb = insert_poll_ready_block(tcx, &mut body);

View file

@ -259,7 +259,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
debug!(" injecting statement {counter_kind:?} for {bb:?}");
let data = &mut mir_body[bb];
let source_info = data.terminator().source_info;
let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) };
let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind));
data.statements.insert(0, statement);
}

View file

@ -68,14 +68,13 @@ impl<'tcx> MockBlocks<'tcx> {
BytePos(1)
};
let next_hi = next_lo + BytePos(1);
self.blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.blocks.push(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)),
kind,
}),
is_cleanup: false,
})
false,
))
}
fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) {

View file

@ -55,8 +55,8 @@ fn has_back_edge(
}
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
basic_block_data.statements.push(Statement {
source_info: basic_block_data.terminator().source_info,
kind: StatementKind::ConstEvalCounter,
});
basic_block_data.statements.push(Statement::new(
basic_block_data.terminator().source_info,
StatementKind::ConstEvalCounter,
));
}

View file

@ -222,15 +222,14 @@ where
let span = self.source_info.span;
let pin_obj_bb = bb.unwrap_or_else(|| {
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
// Temporary terminator, will be replaced by patch
source_info: self.source_info,
kind: TerminatorKind::Return,
}),
is_cleanup: false,
})
false,
))
});
let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only {
@ -366,10 +365,8 @@ where
call_statements.push(self.assign(obj_ptr_place, addr));
obj_ptr_place
};
call_statements.push(Statement {
source_info: self.source_info,
kind: StatementKind::StorageLive(fut.local),
});
call_statements
.push(Statement::new(self.source_info, StatementKind::StorageLive(fut.local)));
let call_drop_bb = self.new_block_with_statements(
unwind,
@ -732,17 +729,17 @@ where
let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline);
let setup_bbd = BasicBlockData {
statements: vec![self.assign(
let setup_bbd = BasicBlockData::new_stmts(
vec![self.assign(
Place::from(ptr_local),
Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty),
)],
terminator: Some(Terminator {
Some(Terminator {
kind: TerminatorKind::Goto { target: do_drop_bb },
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
self.elaborator.patch().new_block(setup_bbd)
}
@ -753,14 +750,13 @@ where
args: GenericArgsRef<'tcx>,
) -> BasicBlock {
if adt.variants().is_empty() {
return self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
return self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Unreachable,
}),
is_cleanup: self.unwind.is_cleanup(),
});
self.unwind.is_cleanup(),
));
}
let skip_contents = adt.is_union() || adt.is_manually_drop();
@ -927,9 +923,9 @@ where
let discr_ty = adt.repr().discr_type().to_ty(self.tcx());
let discr = Place::from(self.new_temp(discr_ty));
let discr_rv = Rvalue::Discriminant(self.place);
let switch_block = BasicBlockData {
statements: vec![self.assign(discr, discr_rv)],
terminator: Some(Terminator {
let switch_block = BasicBlockData::new_stmts(
vec![self.assign(discr, discr_rv)],
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::SwitchInt {
discr: Operand::Move(discr),
@ -939,8 +935,8 @@ where
),
},
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
let switch_block = self.elaborator.patch().new_block(switch_block);
self.drop_flag_test_block(switch_block, succ, unwind)
}
@ -956,8 +952,8 @@ where
let ref_place = self.new_temp(ref_ty);
let unit_temp = Place::from(self.new_temp(tcx.types.unit));
let result = BasicBlockData {
statements: vec![self.assign(
let result = BasicBlockData::new_stmts(
vec![self.assign(
Place::from(ref_place),
Rvalue::Ref(
tcx.lifetimes.re_erased,
@ -965,7 +961,7 @@ where
self.place,
),
)],
terminator: Some(Terminator {
Some(Terminator {
kind: TerminatorKind::Call {
func: Operand::function_handle(
tcx,
@ -983,8 +979,8 @@ where
},
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
let destructor_block = self.elaborator.patch().new_block(result);
@ -1047,8 +1043,8 @@ where
let can_go = Place::from(self.new_temp(tcx.types.bool));
let one = self.constant_usize(1);
let drop_block = BasicBlockData {
statements: vec![
let drop_block = BasicBlockData::new_stmts(
vec![
self.assign(
ptr,
Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)),
@ -1058,26 +1054,26 @@ where
Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
),
],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
// this gets overwritten by drop elaboration.
kind: TerminatorKind::Unreachable,
}),
};
unwind.is_cleanup(),
);
let drop_block = self.elaborator.patch().new_block(drop_block);
let loop_block = BasicBlockData {
statements: vec![self.assign(
let loop_block = BasicBlockData::new_stmts(
vec![self.assign(
can_go,
Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))),
)],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::if_(move_(can_go), succ, drop_block),
}),
};
unwind.is_cleanup(),
);
let loop_block = self.elaborator.patch().new_block(loop_block);
let place = tcx.mk_place_deref(ptr);
@ -1187,8 +1183,8 @@ where
let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty);
let slice_ptr = self.new_temp(slice_ptr_ty);
let mut delegate_block = BasicBlockData {
statements: vec![
let mut delegate_block = BasicBlockData::new_stmts(
vec![
self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)),
self.assign(
Place::from(slice_ptr),
@ -1202,9 +1198,9 @@ where
),
),
],
is_cleanup: self.unwind.is_cleanup(),
terminator: None,
};
None,
self.unwind.is_cleanup(),
);
let array_place = mem::replace(
&mut self.place,
@ -1246,8 +1242,8 @@ where
};
let zero = self.constant_usize(0);
let block = BasicBlockData {
statements: vec![
let block = BasicBlockData::new_stmts(
vec![
self.assign(
len.into(),
Rvalue::UnaryOp(
@ -1257,12 +1253,12 @@ where
),
self.assign(cur.into(), Rvalue::Use(zero)),
],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Goto { target: loop_block },
}),
};
unwind.is_cleanup(),
);
let drop_block = self.elaborator.patch().new_block(block);
// FIXME(#34708): handle partially-dropped array/slice elements.
@ -1308,14 +1304,13 @@ where
self.source_info.span,
"open drop for unsafe binder shouldn't be encountered",
);
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Unreachable,
}),
is_cleanup: self.unwind.is_cleanup(),
})
self.unwind.is_cleanup(),
))
}
_ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
@ -1434,11 +1429,10 @@ where
}
fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info: self.source_info, kind: k }),
is_cleanup: unwind.is_cleanup(),
})
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator { source_info: self.source_info, kind: k }),
unwind.is_cleanup(),
))
}
fn new_block_with_statements(
@ -1447,11 +1441,11 @@ where
statements: Vec<Statement<'tcx>>,
k: TerminatorKind<'tcx>,
) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData {
self.elaborator.patch().new_block(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info: self.source_info, kind: k }),
is_cleanup: unwind.is_cleanup(),
})
Some(Terminator { source_info: self.source_info, kind: k }),
unwind.is_cleanup(),
))
}
fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
@ -1467,9 +1461,6 @@ where
}
fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
Statement {
source_info: self.source_info,
kind: StatementKind::Assign(Box::new((lhs, rhs))),
}
Statement::new(self.source_info, StatementKind::Assign(Box::new((lhs, rhs))))
}
}

View file

@ -1636,7 +1636,7 @@ fn op_to_prop_const<'tcx>(
}
let pointer = mplace.ptr().into_pointer_or_addr().ok()?;
let (prov, offset) = pointer.into_parts();
let (prov, offset) = pointer.prov_and_relative_offset();
let alloc_id = prov.alloc_id();
intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?;

View file

@ -900,10 +900,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
);
let dest_ty = dest.ty(caller_body, tcx);
let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((temp, dest))),
});
caller_body[callsite.block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((temp, dest))),
));
tcx.mk_place_deref(temp)
} else {
destination
@ -947,10 +947,9 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
for local in callee_body.vars_and_temps_iter() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageLive(new_local),
});
caller_body[callsite.block]
.statements
.push(Statement::new(callsite.source_info, StatementKind::StorageLive(new_local)));
}
}
if let Some(block) = return_block {
@ -958,22 +957,22 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
// the slice once.
let mut n = 0;
if remap_destination {
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((
caller_body[block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((
dest,
Rvalue::Use(Operand::Move(destination_local.into())),
))),
});
));
n += 1;
}
for local in callee_body.vars_and_temps_iter().rev() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(new_local),
});
caller_body[block].statements.push(Statement::new(
callsite.source_info,
StatementKind::StorageDead(new_local),
));
n += 1;
}
}
@ -1126,10 +1125,10 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
trace!("creating temp for argument {:?}", arg);
let arg_ty = arg.ty(caller_body, inliner.tcx());
let local = new_call_temp(caller_body, callsite, arg_ty, return_block);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
});
caller_body[callsite.block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
));
local
}
@ -1142,19 +1141,14 @@ fn new_call_temp<'tcx>(
) -> Local {
let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageLive(local),
});
caller_body[callsite.block]
.statements
.push(Statement::new(callsite.source_info, StatementKind::StorageLive(local)));
if let Some(block) = return_block {
caller_body[block].statements.insert(
0,
Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(local),
},
);
caller_body[block]
.statements
.insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local)));
}
local

View file

@ -240,15 +240,15 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
let Some(arg_place) = arg.node.place() else { return };
statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Copy(
arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
)),
))),
});
));
terminator.kind = TerminatorKind::Goto { target: *destination_block };
}

View file

@ -259,13 +259,13 @@ fn remap_mir_for_const_eval_select<'tcx>(
// (const generic stuff) so we just create a temporary and deconstruct
// that.
let local = body.local_decls.push(LocalDecl::new(ty, fn_span));
bb.statements.push(Statement {
source_info: SourceInfo::outermost(fn_span),
kind: StatementKind::Assign(Box::new((
bb.statements.push(Statement::new(
SourceInfo::outermost(fn_span),
StatementKind::Assign(Box::new((
local.into(),
Rvalue::Use(tupled_args.node.clone()),
))),
});
));
(Operand::Move, local.into())
}
Operand::Move(place) => (Operand::Move, place),

View file

@ -25,31 +25,31 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
}
sym::ub_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::contract_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::forget => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
span: terminator.source_info.span,
@ -57,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
const_: Const::zero_sized(tcx.types.unit),
}))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::copy_nonoverlapping => {
@ -65,9 +65,9 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
let Ok([src, dst, count]) = take_array(args) else {
bug!("Wrong arguments for copy_non_overlapping intrinsic");
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Intrinsic(Box::new(
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::CopyNonOverlapping(
rustc_middle::mir::CopyNonOverlapping {
src: src.node,
@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
},
),
)),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::assume => {
@ -84,12 +84,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
let Ok([arg]) = take_array(args) else {
bug!("Wrong arguments for assume intrinsic");
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::Assume(arg.node),
)),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
arg.node,
))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::wrapping_add
@ -121,13 +121,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
sym::unchecked_shr => BinOp::ShrUnchecked,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
@ -141,13 +141,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
sym::mul_with_overflow => BinOp::MulWithOverflow,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::size_of | sym::align_of => {
@ -158,13 +158,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
sym::align_of => NullOp::AlignOf,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(null_op, tp_ty),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::read_via_copy => {
@ -183,13 +183,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
};
// Add new statement at the end of the block that does the read, and patch
// up the terminator.
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Copy(derefed_place)),
))),
});
));
terminator.kind = match *target {
None => {
// No target means this read something uninhabited,
@ -217,13 +217,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
"Only passing a local is supported"
);
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
derefed_place,
Rvalue::Use(val.node),
))),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::discriminant_value => {
@ -236,13 +233,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
};
let arg = arg.node.place().unwrap();
let arg = tcx.mk_place_deref(arg);
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Discriminant(arg),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::offset => {
@ -253,13 +250,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
"Wrong number of arguments for offset intrinsic",
);
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::slice_get_unchecked => {
@ -302,10 +299,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
_ => bug!("Unknown return type {ret_ty:?}"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((*destination, rvalue))),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((*destination, rvalue))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::transmute | sym::transmute_unchecked => {
@ -320,13 +317,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
// Always emit the cast, even if we transmute to an uninhabited type,
// because that lets CTFE and codegen generate better error messages
// when such a transmute actually ends up reachable.
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty),
))),
});
));
if let Some(target) = *target {
terminator.kind = TerminatorKind::Goto { target };
} else {
@ -351,13 +348,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
);
};
let fields = [data.node, meta.node];
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Aggregate(Box::new(kind), fields.into()),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::ptr_metadata => {
@ -368,13 +365,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
);
};
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
_ => {}

View file

@ -56,8 +56,7 @@ fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_ite
// make new RValue for Len
let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone());
let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value)));
let add_statement =
Statement { kind: len_statement_kind, source_info: terminator.source_info };
let add_statement = Statement::new(terminator.source_info, len_statement_kind);
// modify terminator into simple Goto
let new_terminator_kind = TerminatorKind::Goto { target: *bb };

View file

@ -78,14 +78,13 @@ impl<'tcx> MirPatch<'tcx> {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::UnwindResume,
}),
is_cleanup: true,
});
true,
));
self.resume_block = Some(bb);
bb
}
@ -95,14 +94,13 @@ impl<'tcx> MirPatch<'tcx> {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::Unreachable,
}),
is_cleanup: true,
});
true,
));
self.unreachable_cleanup_block = Some(bb);
bb
}
@ -112,14 +110,13 @@ impl<'tcx> MirPatch<'tcx> {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::Unreachable,
}),
is_cleanup: false,
});
false,
));
self.unreachable_no_cleanup_block = Some(bb);
bb
}
@ -131,14 +128,13 @@ impl<'tcx> MirPatch<'tcx> {
return cached_bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::UnwindTerminate(reason),
}),
is_cleanup: true,
});
true,
));
self.terminate_block = Some((bb, reason));
bb
}
@ -280,7 +276,7 @@ impl<'tcx> MirPatch<'tcx> {
let source_info = Self::source_info_for_index(&body[loc.block], loc);
body[loc.block]
.statements
.insert(loc.statement_index, Statement { source_info, kind: stmt });
.insert(loc.statement_index, Statement::new(source_info, stmt));
delta += 1;
}
}

View file

@ -731,23 +731,22 @@ struct Promoter<'a, 'tcx> {
impl<'a, 'tcx> Promoter<'a, 'tcx> {
fn new_block(&mut self) -> BasicBlock {
let span = self.promoted.span;
self.promoted.basic_blocks_mut().push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.promoted.basic_blocks_mut().push(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(span),
kind: TerminatorKind::Return,
}),
is_cleanup: false,
})
false,
))
}
fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
let last = self.promoted.basic_blocks.last_index().unwrap();
let data = &mut self.promoted[last];
data.statements.push(Statement {
source_info: SourceInfo::outermost(span),
kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))),
});
data.statements.push(Statement::new(
SourceInfo::outermost(span),
StatementKind::Assign(Box::new((Place::from(dest), rvalue))),
));
}
fn is_temp_kind(&self, local: Local) -> bool {
@ -914,13 +913,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
let promoted_operand = promoted_operand(ref_ty, span);
let promoted_ref_statement = Statement {
source_info: statement.source_info,
kind: StatementKind::Assign(Box::new((
let promoted_ref_statement = Statement::new(
statement.source_info,
StatementKind::Assign(Box::new((
Place::from(promoted_ref),
Rvalue::Use(Operand::Constant(Box::new(promoted_operand))),
))),
};
);
self.extra_statements.push((loc, promoted_ref_statement));
(

View file

@ -323,9 +323,7 @@ fn dropee_emit_retag<'tcx>(
StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
];
for s in new_statements {
body.basic_blocks_mut()[START_BLOCK]
.statements
.push(Statement { source_info, kind: s });
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, s));
}
}
dropee_ptr
@ -350,11 +348,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
};
block(&mut blocks, TerminatorKind::Goto { target: return_block });
block(&mut blocks, TerminatorKind::Return);
@ -515,17 +509,17 @@ fn build_thread_local_shim<'tcx>(
let span = tcx.def_span(def_id);
let source_info = SourceInfo::outermost(span);
let blocks = IndexVec::from_raw(vec![BasicBlockData {
statements: vec![Statement {
let blocks = IndexVec::from_raw(vec![BasicBlockData::new_stmts(
vec![Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::ThreadLocalRef(def_id),
))),
}],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
}]);
)],
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
)]);
new_body(
MirSource::from_instance(instance),
@ -609,11 +603,11 @@ impl<'tcx> CloneShimBuilder<'tcx> {
is_cleanup: bool,
) -> BasicBlock {
let source_info = self.source_info();
self.blocks.push(BasicBlockData {
self.blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind }),
Some(Terminator { source_info, kind }),
is_cleanup,
})
))
}
/// Gives the index of an upcoming BasicBlock, with an offset.
@ -625,7 +619,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
}
fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
Statement { source_info: self.source_info(), kind }
Statement::new(self.source_info(), kind)
}
fn copy_shim(&mut self) {
@ -901,13 +895,13 @@ fn build_call_shim<'tcx>(
.immutable(),
);
let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default };
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(ref_rcvr),
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
))),
});
));
Operand::Move(Place::from(ref_rcvr))
}
});
@ -956,11 +950,11 @@ fn build_call_shim<'tcx>(
let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind }),
Some(Terminator { source_info, kind }),
is_cleanup,
})
))
};
// BB #0
@ -1071,8 +1065,9 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None);
let variant = adt_def.variant(variant_index);
let statement = Statement {
kind: StatementKind::Assign(Box::new((
let statement = Statement::new(
source_info,
StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::Aggregate(
Box::new(kind),
@ -1081,14 +1076,13 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
.collect(),
),
))),
source_info,
};
);
let start_block = BasicBlockData {
statements: vec![statement],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
let start_block = BasicBlockData::new_stmts(
vec![statement],
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::item(ctor_id);
let mut body = new_body(
@ -1130,16 +1124,16 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
Operand::Move(Place::from(Local::new(1))),
Ty::new_imm_ptr(tcx, tcx.types.unit),
);
let stmt = Statement {
let stmt = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
};
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
);
let statements = vec![stmt];
let start_block = BasicBlockData {
let start_block = BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty));
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
}
@ -1230,16 +1224,16 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
IndexVec::from_raw(fields),
);
let stmt = Statement {
let stmt = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
};
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
);
let statements = vec![stmt];
let start_block = BasicBlockData {
let start_block = BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,

View file

@ -88,11 +88,7 @@ pub(super) fn build_async_drop_shim<'tcx>(
let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
};
block(
&mut blocks,
@ -133,7 +129,7 @@ pub(super) fn build_async_drop_shim<'tcx>(
dropee_ptr,
Rvalue::Use(Operand::Move(coroutine_layout_dropee)),
)));
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement { source_info, kind: st_kind });
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span);
let dropline = body.basic_blocks.last_index();
@ -240,13 +236,13 @@ fn build_adrop_for_coroutine_shim<'tcx>(
.project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(proxy_ref_local),
Rvalue::CopyForDeref(proxy_ref_place),
))),
},
),
);
idx += 1;
let mut cor_ptr_local = proxy_ref_local;
@ -261,13 +257,13 @@ fn build_adrop_for_coroutine_shim<'tcx>(
// _cor_ptr = _proxy.0.0 (... .0)
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(cor_ptr_local),
Rvalue::CopyForDeref(impl_ptr_place),
))),
},
),
);
idx += 1;
}
@ -281,10 +277,10 @@ fn build_adrop_for_coroutine_shim<'tcx>(
);
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))),
},
StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))),
),
);
}
body
@ -334,13 +330,13 @@ fn build_adrop_for_adrop_shim<'tcx>(
let mut statements = Vec::new();
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(proxy_ref_local),
Rvalue::CopyForDeref(proxy_ref_place),
))),
});
));
let mut cor_ptr_local = proxy_ref_local;
proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
@ -350,13 +346,13 @@ fn build_adrop_for_adrop_shim<'tcx>(
.project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
// _cor_ptr = _proxy.0.0 (... .0)
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(cor_ptr_local),
Rvalue::CopyForDeref(impl_ptr_place),
))),
});
));
}
});
@ -367,10 +363,10 @@ fn build_adrop_for_adrop_shim<'tcx>(
tcx.mk_place_deref(Place::from(cor_ptr_local)),
);
let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
});
StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
));
// cor_pin_ty = `Pin<&mut cor_ref>`
let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
@ -378,9 +374,9 @@ fn build_adrop_for_adrop_shim<'tcx>(
let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
// call Pin<FutTy>::new_unchecked(&mut impl_cor)
blocks.push(BasicBlockData {
blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator {
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span),
@ -392,15 +388,14 @@ fn build_adrop_for_adrop_shim<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
false,
));
// When dropping async drop coroutine, we continue its execution:
// we call impl::poll (impl_layout, ctx)
let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
let resume_ctx = Place::from(Local::new(2));
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
blocks.push(BasicBlockData::new(
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span),
@ -416,13 +411,12 @@ fn build_adrop_for_adrop_shim<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});
false,
));
blocks.push(BasicBlockData::new(
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
));
let source = MirSource::from_instance(instance);
let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);

View file

@ -115,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
for bb_idx in new_targets.all_targets() {
storage_deads_to_insert.push((
*bb_idx,
Statement {
source_info: terminator.source_info,
kind: StatementKind::StorageDead(opt.to_switch_on.local),
},
Statement::new(
terminator.source_info,
StatementKind::StorageDead(opt.to_switch_on.local),
),
));
}
}

View file

@ -383,10 +383,10 @@ where
let mut candidates = vec![];
if let TypingMode::Coherence = self.typing_mode() {
if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
return vec![candidate];
}
if let TypingMode::Coherence = self.typing_mode()
&& let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
{
return vec![candidate];
}
self.assemble_alias_bound_candidates(goal, &mut candidates);

View file

@ -997,12 +997,12 @@ where
}
fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> {
if let ty::Alias(ty::Projection, alias_ty) = ty.kind() {
if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? {
return Ok(term.expect_ty());
}
if let ty::Alias(ty::Projection, alias_ty) = ty.kind()
&& let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())?
{
Ok(term.expect_ty())
} else {
ty.try_super_fold_with(self)
}
ty.try_super_fold_with(self)
}
}

View file

@ -42,20 +42,18 @@ where
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(host_clause) = assumption.as_host_effect_clause() {
if host_clause.def_id() == goal.predicate.def_id()
&& host_clause.constness().satisfies(goal.predicate.constness)
{
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
host_clause.skip_binder().trait_ref.args,
) {
return Ok(());
}
}
if let Some(host_clause) = assumption.as_host_effect_clause()
&& host_clause.def_id() == goal.predicate.def_id()
&& host_clause.constness().satisfies(goal.predicate.constness)
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
host_clause.skip_binder().trait_ref.args,
)
{
Ok(())
} else {
Err(NoSolution)
}
Err(NoSolution)
}
fn match_assumption(

View file

@ -429,22 +429,21 @@ where
// If we have run this goal before, and it was stalled, check that any of the goal's
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
// stalled, since it'll canonicalize the same way and evaluation is pure.
if let Some(stalled_on) = stalled_on {
if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !self
.delegate
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
}
if let Some(stalled_on) = stalled_on
&& !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !self
.delegate
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
}
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
@ -833,14 +832,11 @@ where
match t.kind() {
ty::Infer(ty::TyVar(vid)) => {
if let ty::TermKind::Ty(term) = self.term.kind() {
if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
if self.delegate.root_ty_var(vid)
== self.delegate.root_ty_var(term_vid)
{
return ControlFlow::Break(());
}
}
if let ty::TermKind::Ty(term) = self.term.kind()
&& let ty::Infer(ty::TyVar(term_vid)) = term.kind()
&& self.delegate.root_ty_var(vid) == self.delegate.root_ty_var(term_vid)
{
return ControlFlow::Break(());
}
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
@ -860,15 +856,12 @@ where
fn visit_const(&mut self, c: I::Const) -> Self::Result {
match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
if let ty::TermKind::Const(term) = self.term.kind() {
if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
{
if self.delegate.root_const_var(vid)
== self.delegate.root_const_var(term_vid)
{
return ControlFlow::Break(());
}
}
if let ty::TermKind::Const(term) = self.term.kind()
&& let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
&& self.delegate.root_const_var(vid)
== self.delegate.root_const_var(term_vid)
{
return ControlFlow::Break(());
}
self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())

View file

@ -112,18 +112,17 @@ where
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.item_def_id() == goal.predicate.def_id() {
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.alias.args,
projection_pred.skip_binder().projection_term.args,
) {
return Ok(());
}
}
if let Some(projection_pred) = assumption.as_projection_clause()
&& projection_pred.item_def_id() == goal.predicate.def_id()
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.alias.args,
projection_pred.skip_binder().projection_term.args,
)
{
Ok(())
} else {
Err(NoSolution)
}
Err(NoSolution)
}
fn match_assumption(

View file

@ -127,33 +127,32 @@ where
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(trait_clause) = assumption.as_trait_clause() {
if trait_clause.polarity() != goal.predicate.polarity {
return Err(NoSolution);
}
if trait_clause.def_id() == goal.predicate.def_id() {
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
trait_clause.skip_binder().trait_ref.args,
) {
return Ok(());
}
}
fn trait_def_id_matches<I: Interner>(
cx: I,
clause_def_id: I::DefId,
goal_def_id: I::DefId,
) -> bool {
clause_def_id == goal_def_id
// PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
// check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
// are syntactic sugar for a lack of bounds so don't need this.
if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
&& ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
{
let meta_sized_clause =
trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
return Self::fast_reject_assumption(ecx, goal, meta_sized_clause);
}
// check for a `MetaSized` supertrait being matched against a `Sized` assumption.
//
// `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this.
|| (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
&& cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized))
}
Err(NoSolution)
if let Some(trait_clause) = assumption.as_trait_clause()
&& trait_clause.polarity() == goal.predicate.polarity
&& trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id())
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
trait_clause.skip_binder().trait_ref.args,
)
{
return Ok(());
} else {
Err(NoSolution)
}
}
fn match_assumption(

View file

@ -177,6 +177,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
self.check_align(span, target, *align, *repr_span)
}
Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => {
self.check_link_section(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
self.check_naked(hir_id, *attr_span, span, target)
}
@ -286,7 +289,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
[sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
[sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
self.check_macro_use(hir_id, attr, target)
}
@ -1831,7 +1833,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
/// Checks if `#[link_section]` is applied to a function or static.
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@ -1839,7 +1841,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section");
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section");
}
_ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
@ -1847,7 +1849,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
attr_span,
errors::LinkSection { span },
);
}

View file

@ -320,10 +320,10 @@ pub fn supertrait_def_ids<I: Interner>(
let trait_def_id = stack.pop()?;
for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() {
if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
if set.insert(data.def_id()) {
stack.push(data.def_id());
}
if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder()
&& set.insert(data.def_id())
{
stack.push(data.def_id());
}
}

View file

@ -117,12 +117,20 @@ impl<I: Interner> TypingMode<I> {
}
pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
let defining_opaque_types = cx.opaque_types_defined_by(body_def_id);
if defining_opaque_types.is_empty() {
TypingMode::non_body_analysis()
} else {
TypingMode::Borrowck { defining_opaque_types }
}
}
pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
TypingMode::PostBorrowckAnalysis {
defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
let defined_opaque_types = cx.opaque_types_defined_by(body_def_id);
if defined_opaque_types.is_empty() {
TypingMode::non_body_analysis()
} else {
TypingMode::PostBorrowckAnalysis { defined_opaque_types }
}
}
}

View file

@ -284,12 +284,12 @@ where
}
// If they have no bound vars, relate normally.
if let Some(a_inner) = a.no_bound_vars() {
if let Some(b_inner) = b.no_bound_vars() {
self.relate(a_inner, b_inner)?;
return Ok(a);
}
};
if let Some(a_inner) = a.no_bound_vars()
&& let Some(b_inner) = b.no_bound_vars()
{
self.relate(a_inner, b_inner)?;
return Ok(a);
}
match self.ambient_variance {
// Checks whether `for<..> sub <: for<..> sup` holds.

View file

@ -80,31 +80,29 @@ impl<X: Cx> GlobalCache<X> {
mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
) -> Option<CacheData<'a, X>> {
let entry = self.map.get(&input)?;
if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success {
if available_depth.cache_entry_is_applicable(required_depth)
&& candidate_is_applicable(nested_goals)
{
return Some(CacheData {
result: cx.get_tracked(&result),
required_depth,
encountered_overflow: false,
nested_goals,
});
}
if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success
&& available_depth.cache_entry_is_applicable(required_depth)
&& candidate_is_applicable(nested_goals)
{
return Some(CacheData {
result: cx.get_tracked(&result),
required_depth,
encountered_overflow: false,
nested_goals,
});
}
let additional_depth = available_depth.0;
if let Some(WithOverflow { nested_goals, result }) =
entry.with_overflow.get(&additional_depth)
&& candidate_is_applicable(nested_goals)
{
if candidate_is_applicable(nested_goals) {
return Some(CacheData {
result: cx.get_tracked(result),
required_depth: additional_depth,
encountered_overflow: true,
nested_goals,
});
}
return Some(CacheData {
result: cx.get_tracked(result),
required_depth: additional_depth,
encountered_overflow: true,
nested_goals,
});
}
None

View file

@ -742,7 +742,7 @@ impl TypeId {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
let t: u128 = intrinsics::type_id::<T>();
let t: u128 = const { intrinsics::type_id::<T>() };
let t1 = (t >> 64) as u64;
let t2 = t as u64;
@ -824,7 +824,7 @@ impl fmt::Debug for TypeId {
#[stable(feature = "type_name", since = "1.38.0")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
intrinsics::type_name::<T>()
const { intrinsics::type_name::<T>() }
}
/// Returns the type name of the pointed-to value as a string slice.

View file

@ -839,10 +839,10 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
/// If the actual type neither requires drop glue nor implements
/// `Copy`, then the return value of this function is unspecified.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart) wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
#[rustc_intrinsic_const_stable_indirect]
@ -2655,10 +2655,10 @@ pub const fn align_of<T>() -> usize;
/// Returns the number of variants of the type `T` cast to a `usize`;
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart) wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
#[rustc_nounwind]
@ -2694,10 +2694,10 @@ pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
/// Gets a static string slice containing the name of a type.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart) wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`core::any::type_name`].
#[rustc_nounwind]
@ -2709,10 +2709,10 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
/// function will return the same value for a type regardless of whichever
/// crate it is invoked in.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
/// Note that, unlike most intrinsics, this can only be called at compile-time
/// as backends do not have an implementation for it. The only caller (its
/// stable counterpart) wraps this intrinsic call in a `const` block so that
/// backends only see an evaluated constant.
///
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
#[rustc_nounwind]

View file

@ -616,7 +616,7 @@ pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
#[rustc_const_stable(feature = "const_mem_needs_drop", since = "1.36.0")]
#[rustc_diagnostic_item = "needs_drop"]
pub const fn needs_drop<T: ?Sized>() -> bool {
intrinsics::needs_drop::<T>()
const { intrinsics::needs_drop::<T>() }
}
/// Returns the value of type `T` represented by the all-zero byte-pattern.
@ -1215,7 +1215,7 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_diagnostic_item = "mem_variant_count"]
pub const fn variant_count<T>() -> usize {
intrinsics::variant_count::<T>()
const { intrinsics::variant_count::<T>() }
}
/// Provides associated constants for various useful properties of types,

View file

@ -316,6 +316,11 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")]
mod prim_never {}
// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
impl ! {}
#[rustc_doc_primitive = "char"]
#[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type.

View file

@ -33,7 +33,7 @@ use core::sync::atomic::{Atomic, AtomicU32, Ordering};
use super::{AsRawHandle, DirBuff, File, FromRawHandle};
use crate::sys::c;
use crate::sys::pal::api::WinError;
use crate::sys::pal::api::{UnicodeStrRef, WinError, unicode_str};
use crate::thread;
// The maximum number of times to spin when waiting for deletes to complete.
@ -74,7 +74,7 @@ unsafe fn nt_open_file(
/// `options` will be OR'd with `FILE_OPEN_REPARSE_POINT`.
fn open_link_no_reparse(
parent: &File,
path: &[u16],
path: UnicodeStrRef<'_>,
access: u32,
options: u32,
) -> Result<Option<File>, WinError> {
@ -90,9 +90,8 @@ fn open_link_no_reparse(
static ATTRIBUTES: Atomic<u32> = AtomicU32::new(c::OBJ_DONT_REPARSE);
let result = unsafe {
let mut path_str = c::UNICODE_STRING::from_ref(path);
let mut object = c::OBJECT_ATTRIBUTES {
ObjectName: &mut path_str,
ObjectName: path.as_ptr(),
RootDirectory: parent.as_raw_handle(),
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
..c::OBJECT_ATTRIBUTES::with_length()
@ -129,7 +128,7 @@ fn open_link_no_reparse(
}
}
fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> {
fn open_dir(parent: &File, name: UnicodeStrRef<'_>) -> Result<Option<File>, WinError> {
// Open the directory for synchronous directory listing.
open_link_no_reparse(
parent,
@ -140,7 +139,7 @@ fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> {
)
}
fn delete(parent: &File, name: &[u16]) -> Result<(), WinError> {
fn delete(parent: &File, name: UnicodeStrRef<'_>) -> Result<(), WinError> {
// Note that the `delete` function consumes the opened file to ensure it's
// dropped immediately. See module comments for why this is important.
match open_link_no_reparse(parent, name, c::DELETE, 0) {
@ -179,8 +178,9 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
'outer: while let Some(dir) = dirlist.pop() {
let more_data = dir.fill_dir_buff(&mut buffer, restart)?;
for (name, is_directory) in buffer.iter() {
let name = unicode_str!(&name);
if is_directory {
let Some(subdir) = open_dir(&dir, &name)? else { continue };
let Some(subdir) = open_dir(&dir, name)? else { continue };
dirlist.push(dir);
dirlist.push(subdir);
continue 'outer;
@ -188,7 +188,7 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
// Attempt to delete, retrying on sharing violation errors as these
// can often be very temporary. E.g. if something takes just a
// bit longer than expected to release a file handle.
retry(|| delete(&dir, &name), WinError::SHARING_VIOLATION)?;
retry(|| delete(&dir, name), WinError::SHARING_VIOLATION)?;
}
}
if more_data {
@ -197,7 +197,8 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
} else {
// Attempt to delete, retrying on not empty errors because we may
// need to wait some time for files to be removed from the filesystem.
retry(|| delete(&dir, &[]), WinError::DIR_NOT_EMPTY)?;
let name = unicode_str!("");
retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?;
restart = true;
}
}

View file

@ -30,6 +30,7 @@
//! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example.
use core::ffi::c_void;
use core::marker::PhantomData;
use super::c;
@ -291,3 +292,75 @@ impl WinError {
pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT);
// tidy-alphabetical-end
}
/// A wrapper around a UNICODE_STRING that is equivalent to `&[u16]`.
///
/// It is preferable to use the `unicode_str!` macro as that contains mitigations for #143078.
///
/// If the MaximumLength field of the underlying UNICODE_STRING is greater than
/// the Length field then you can test if the string is null terminated by inspecting
/// the u16 directly after the string. You cannot otherwise depend on nul termination.
#[derive(Copy, Clone)]
pub struct UnicodeStrRef<'a> {
s: c::UNICODE_STRING,
lifetime: PhantomData<&'a [u16]>,
}
static EMPTY_STRING_NULL_TERMINATED: &[u16] = &[0];
impl UnicodeStrRef<'_> {
const fn new(slice: &[u16], is_null_terminated: bool) -> Self {
let (len, max_len, ptr) = if slice.is_empty() {
(0, 2, EMPTY_STRING_NULL_TERMINATED.as_ptr().cast_mut())
} else {
let len = slice.len() - (is_null_terminated as usize);
(len * 2, size_of_val(slice), slice.as_ptr().cast_mut())
};
Self {
s: c::UNICODE_STRING { Length: len as _, MaximumLength: max_len as _, Buffer: ptr },
lifetime: PhantomData,
}
}
pub const fn from_slice_with_nul(slice: &[u16]) -> Self {
if !slice.is_empty() {
debug_assert!(slice[slice.len() - 1] == 0);
}
Self::new(slice, true)
}
pub const fn from_slice(slice: &[u16]) -> Self {
Self::new(slice, false)
}
/// Returns a pointer to the underlying UNICODE_STRING
pub const fn as_ptr(&self) -> *const c::UNICODE_STRING {
&self.s
}
}
/// Create a UnicodeStringRef from a literal str or a u16 array.
///
/// To mitigate #143078, when using a literal str the created UNICODE_STRING
/// will be nul terminated. The MaximumLength field of the UNICODE_STRING will
/// be set greater than the Length field to indicate that a nul may be present.
///
/// If using a u16 array, the array is used exactly as provided and you cannot
/// count on the string being nul terminated.
/// This should generally be used for strings that come from the OS.
///
/// **NOTE:** we lack a UNICODE_STRING builder type as we don't currently have
/// a use for it. If needing to dynamically build a UNICODE_STRING, the builder
/// should try to ensure there's a nul one past the end of the string.
pub macro unicode_str {
($str:literal) => {const {
crate::sys::pal::windows::api::UnicodeStrRef::from_slice_with_nul(
crate::sys::pal::windows::api::wide_str!($str),
)
}},
($array:expr) => {
crate::sys::pal::windows::api::UnicodeStrRef::from_slice(
$array,
)
}
}

View file

@ -37,13 +37,6 @@ pub fn nt_success(status: NTSTATUS) -> bool {
status >= 0
}
impl UNICODE_STRING {
pub fn from_ref(slice: &[u16]) -> Self {
let len = size_of_val(slice);
Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
}
}
impl OBJECT_ATTRIBUTES {
pub fn with_length() -> Self {
Self {

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